From 9ce92af76fc68ede0d9973d9bff3237c076e7362 Mon Sep 17 00:00:00 2001 From: Sworld <61224072+mcthesw@users.noreply.github.com> Date: Fri, 27 Sep 2024 21:07:11 +0800 Subject: [PATCH 01/11] =?UTF-8?q?refactor:=20=E5=90=8E=E7=AB=AF=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/en_US.json | 8 +- locales/fr.json | 6 +- locales/ko.json | 6 +- locales/zh_SIMPLIFIED.json | 8 +- pnpm-lock.yaml | 3744 ++++++++----------- src-tauri/src/{ => backup}/archive.rs | 10 +- src-tauri/src/{backup.rs => backup/game.rs} | 150 +- src-tauri/src/backup/game_snapshots.rs | 14 + src-tauri/src/backup/mod.rs | 13 + src-tauri/src/backup/save_unit.rs | 20 + src-tauri/src/backup/snapshot.rs | 11 + src-tauri/src/backup/utils.rs | 80 + src-tauri/src/cloud.rs | 219 -- src-tauri/src/cloud_sync/backend.rs | 106 + src-tauri/src/cloud_sync/cloud_settings.rs | 31 + src-tauri/src/cloud_sync/mod.rs | 7 + src-tauri/src/cloud_sync/utils.rs | 91 + src-tauri/src/config.rs | 239 -- src-tauri/src/config/config.rs | 62 + src-tauri/src/config/mod.rs | 7 + src-tauri/src/config/settings.rs | 44 + src-tauri/src/config/utils.rs | 104 + src-tauri/src/default_value.rs | 2 +- src-tauri/src/ipc_handler.rs | 38 +- src-tauri/src/main.rs | 18 +- src-tauri/src/tray.rs | 15 +- src/views/GameManage.vue | 24 +- 27 files changed, 2209 insertions(+), 2868 deletions(-) rename src-tauri/src/{ => backup}/archive.rs (95%) rename src-tauri/src/{backup.rs => backup/game.rs} (62%) create mode 100644 src-tauri/src/backup/game_snapshots.rs create mode 100644 src-tauri/src/backup/mod.rs create mode 100644 src-tauri/src/backup/save_unit.rs create mode 100644 src-tauri/src/backup/snapshot.rs create mode 100644 src-tauri/src/backup/utils.rs delete mode 100644 src-tauri/src/cloud.rs create mode 100644 src-tauri/src/cloud_sync/backend.rs create mode 100644 src-tauri/src/cloud_sync/cloud_settings.rs create mode 100644 src-tauri/src/cloud_sync/mod.rs create mode 100644 src-tauri/src/cloud_sync/utils.rs delete mode 100644 src-tauri/src/config.rs create mode 100644 src-tauri/src/config/config.rs create mode 100644 src-tauri/src/config/mod.rs create mode 100644 src-tauri/src/config/settings.rs create mode 100644 src-tauri/src/config/utils.rs diff --git a/locales/en_US.json b/locales/en_US.json index 2f91e4f..0229a7f 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -230,10 +230,10 @@ "choose_save_file_error": "An error occurred while selecting the save file", "choose_executable_file_error": "An error occurred while selecting an executable file", "add_game_failed": "Failed to add game", - "get_backup_list_failed": "Failed to obtain backup information", + "get_game_snapshots_failed": "Failed to obtain backup information", "backup_failed": "Backup failed, check logs for more information", - "delete_backup_failed": "Delete backup failed, check logs for more information", - "apply_backup_failed": "Apply backup failed, check logs for more information", + "delete_snapshot_failed": "Delete backup failed, check logs for more information", + "restore_snapshot_failed": "Apply backup failed, check logs for more information", "delete_game_failed": "Failed to delete game", "open_backup_folder_failed": "Failed to open backup folder", "set_config_failed": "Failed to set config", @@ -286,4 +286,4 @@ "enable_edit": "Enable editing: You can drag and drop items directly to sort them", "game_not_found": "It is recommended to delete this collection as the game does not exist:" } -} +} \ No newline at end of file diff --git a/locales/fr.json b/locales/fr.json index 6c680aa..f983d1e 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -217,10 +217,10 @@ "choose_save_file_error": "Misappropriation dans la sélection des documents archivés", "choose_executable_file_error": "Manquement dans la sélection d ' un document exécutoire", "add_game_failed": "Synchronisation cellulaire", - "get_backup_list_failed": "Failure to obtain back-up information", + "get_game_snapshots_failed": "Failure to obtain back-up information", "backup_failed": "Intervalles de sauvegarde automatiques", - "delete_backup_failed": "Points d ' addition réussis", - "apply_backup_failed": "Défauts d'application, registres d'inspection pour obtenir plus d'information", + "delete_snapshot_failed": "Points d ' addition réussis", + "restore_snapshot_failed": "Défauts d'application, registres d'inspection pour obtenir plus d'information", "delete_game_failed": "Supprimer l'échec du jeu", "open_backup_folder_failed": "Défaut d ' ouvrir les documents", "set_config_failed": "Absence de configuration", diff --git a/locales/ko.json b/locales/ko.json index 14d33d8..0dfc61a 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -185,15 +185,15 @@ "overwrite_download": "Coverage 다운로드" }, "error": { - "delete_backup_failed": "성공적인 추가 포인트", - "apply_backup_failed": "신청 실패, 검사 로그는 더 많은 정보를 얻기 위하여", + "delete_snapshot_failed": "성공적인 추가 포인트", + "restore_snapshot_failed": "신청 실패, 검사 로그는 더 많은 정보를 얻기 위하여", "open_url_failed": "링크 열기 실패", "config_load_failed": "문서의 실패는 문서가 유효하지 않았거나 사용할 수없는 사실로 인해 될 수 있습니다", "choose_save_dir_error": "아카이브 문서의 선택에 실수", "choose_save_file_error": "아카이브 문서의 선택에 실수", "choose_executable_file_error": "시행 문서의 선택에 실수", "add_game_failed": "게임 실패 추가", - "get_backup_list_failed": "백업 정보를 얻기 위해 실패", + "get_game_snapshots_failed": "백업 정보를 얻기 위해 실패", "backup_failed": "자동 백업 간격", "delete_game_failed": "게임 실패 삭제", "open_backup_folder_failed": "다시 문서를 열 실패", diff --git a/locales/zh_SIMPLIFIED.json b/locales/zh_SIMPLIFIED.json index 0f55ad3..2095d58 100644 --- a/locales/zh_SIMPLIFIED.json +++ b/locales/zh_SIMPLIFIED.json @@ -230,10 +230,10 @@ "choose_save_file_error": "选择存档文件时发生错误", "choose_executable_file_error": "选择可执行文件时发生错误", "add_game_failed": "添加游戏失败", - "get_backup_list_failed": "获取备份信息失败", + "get_game_snapshots_failed": "获取备份信息失败", "backup_failed": "备份失败,检查日志以获取更多信息", - "delete_backup_failed": "删除备份失败,检查日志以获取更多信息", - "apply_backup_failed": "应用备份失败,检查日志以获取更多信息", + "delete_snapshot_failed": "删除备份失败,检查日志以获取更多信息", + "restore_snapshot_failed": "应用备份失败,检查日志以获取更多信息", "delete_game_failed": "删除游戏失败", "open_backup_folder_failed": "打开备份文件夹失败", "set_config_failed": "设置配置失败", @@ -286,4 +286,4 @@ "game_not_found": "建议删除该收藏,因为游戏不存在:", "enable_edit": "启用编辑:可以直接拖拽项目进行排序" } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1f07053..069b4c1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,1167 +1,1765 @@ -lockfileVersion: '9.0' +lockfileVersion: '6.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -importers: - - .: - dependencies: - '@element-plus/icons-vue': - specifier: ^2.3.1 - version: 2.3.1(vue@3.4.27(typescript@5.4.5)) - '@tauri-apps/api': - specifier: ^1.5.6 - version: 1.5.6 - '@vueuse/core': - specifier: ^10.10.0 - version: 10.10.0(vue@3.4.27(typescript@5.4.5)) - element-plus: - specifier: ^2.7.4 - version: 2.7.4(vue@3.4.27(typescript@5.4.5)) - pinia: - specifier: ^2.1.7 - version: 2.1.7(typescript@5.4.5)(vue@3.4.27(typescript@5.4.5)) - uuid: - specifier: ^9.0.1 - version: 9.0.1 - vue: - specifier: ^3.4.27 - version: 3.4.27(typescript@5.4.5) - vue-i18n: - specifier: ^9.13.1 - version: 9.13.1(vue@3.4.27(typescript@5.4.5)) - vue-router: - specifier: ^4.3.2 - version: 4.3.2(vue@3.4.27(typescript@5.4.5)) - vuedraggable: - specifier: ^4.1.0 - version: 4.1.0(vue@3.4.27(typescript@5.4.5)) - devDependencies: - '@actions/github': - specifier: ^5.1.1 - version: 5.1.1 - '@tauri-apps/cli': - specifier: ^1.5.14 - version: 1.5.14 - '@types/node': - specifier: ^18.19.34 - version: 18.19.34 - '@types/uuid': - specifier: ^9.0.8 - version: 9.0.8 - '@vitejs/plugin-vue': - specifier: ^4.6.2 - version: 4.6.2(vite@4.5.3(@types/node@18.19.34))(vue@3.4.27(typescript@5.4.5)) - adm-zip: - specifier: ^0.5.14 - version: 0.5.14 - fs-extra: - specifier: ^10.1.0 - version: 10.1.0 - typescript: - specifier: ^5.4.5 - version: 5.4.5 - unplugin-auto-import: - specifier: ^0.14.4 - version: 0.14.4(@vueuse/core@10.10.0(vue@3.4.27(typescript@5.4.5)))(rollup@4.21.0) - unplugin-vue-components: - specifier: ^0.24.1 - version: 0.24.1(@babel/parser@7.25.3)(@nuxt/kit@3.12.4(rollup@4.21.0))(rollup@4.21.0)(vue@3.4.27(typescript@5.4.5)) - vite: - specifier: ^4.5.3 - version: 4.5.3(@types/node@18.19.34) - vue-tsc: - specifier: ^2.0.29 - version: 2.0.29(typescript@5.4.5) +dependencies: + '@element-plus/icons-vue': + specifier: ^2.3.1 + version: 2.3.1(vue@3.5.9) + '@tauri-apps/api': + specifier: ^1.5.6 + version: 1.6.0 + '@vueuse/core': + specifier: ^10.10.0 + version: 10.11.1(vue@3.5.9) + element-plus: + specifier: ^2.7.4 + version: 2.8.3(vue@3.5.9) + pinia: + specifier: ^2.1.7 + version: 2.2.2(typescript@5.6.2)(vue@3.5.9) + uuid: + specifier: ^9.0.1 + version: 9.0.1 + vue: + specifier: ^3.4.27 + version: 3.5.9(typescript@5.6.2) + vue-i18n: + specifier: ^9.13.1 + version: 9.14.1(vue@3.5.9) + vue-router: + specifier: ^4.3.2 + version: 4.4.5(vue@3.5.9) + vuedraggable: + specifier: ^4.1.0 + version: 4.1.0(vue@3.5.9) + +devDependencies: + '@actions/github': + specifier: ^5.1.1 + version: 5.1.1 + '@tauri-apps/cli': + specifier: ^1.5.14 + version: 1.6.2 + '@types/node': + specifier: ^18.19.34 + version: 18.19.53 + '@types/uuid': + specifier: ^9.0.8 + version: 9.0.8 + '@vitejs/plugin-vue': + specifier: ^4.6.2 + version: 4.6.2(vite@4.5.5)(vue@3.5.9) + adm-zip: + specifier: ^0.5.14 + version: 0.5.16 + fs-extra: + specifier: ^10.1.0 + version: 10.1.0 + typescript: + specifier: ^5.4.5 + version: 5.6.2 + unplugin-auto-import: + specifier: ^0.14.4 + version: 0.14.4(@vueuse/core@10.11.1) + unplugin-vue-components: + specifier: ^0.24.1 + version: 0.24.1(vue@3.5.9) + vite: + specifier: ^4.5.3 + version: 4.5.5(@types/node@18.19.53) + vue-tsc: + specifier: ^2.0.29 + version: 2.1.6(typescript@5.6.2) packages: - '@actions/github@5.1.1': + /@actions/github@5.1.1: resolution: {integrity: sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==} + dependencies: + '@actions/http-client': 2.2.2 + '@octokit/core': 3.6.0 + '@octokit/plugin-paginate-rest': 2.21.3(@octokit/core@3.6.0) + '@octokit/plugin-rest-endpoint-methods': 5.16.2(@octokit/core@3.6.0) + transitivePeerDependencies: + - encoding + dev: true - '@actions/http-client@2.2.1': - resolution: {integrity: sha512-KhC/cZsq7f8I4LfZSJKgCvEwfkE8o1538VoBeoGzokVLLnbFDEAdFD3UhoMklxo2un9NJVBdANOresx7vTHlHw==} + /@actions/http-client@2.2.2: + resolution: {integrity: sha512-2TvX5LskKQzDDQI+bobIDGAjkn0NJiQlg4MTrKnZ8HfQ7nDEUbtJ1ytxPDb2bfk3Hr2XD99X8oAJISAmIoiSAQ==} + dependencies: + tunnel: 0.0.6 + undici: 5.28.4 + dev: true - '@ampproject/remapping@2.3.0': + /@ampproject/remapping@2.3.0: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + dev: true - '@antfu/utils@0.7.8': - resolution: {integrity: sha512-rWQkqXRESdjXtc+7NRfK9lASQjpXJu1ayp7qi1d23zZorY+wBHVLHHoVcMsEnkqEBWTFqbztO7/QdJFzyEcLTg==} + /@antfu/utils@0.7.10: + resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==} + dev: true - '@babel/code-frame@7.24.7': + /@babel/code-frame@7.24.7: resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.24.7 + picocolors: 1.1.0 + dev: true - '@babel/compat-data@7.24.7': - resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.24.7': - resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.24.7': - resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.24.7': - resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==} + /@babel/compat-data@7.25.4: + resolution: {integrity: sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==} engines: {node: '>=6.9.0'} + dev: true - '@babel/helper-environment-visitor@7.24.7': - resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} + /@babel/core@7.25.2: + resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==} engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.6 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) + '@babel/helpers': 7.25.6 + '@babel/parser': 7.25.6 + '@babel/template': 7.25.0 + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + convert-source-map: 2.0.0 + debug: 4.3.7 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true - '@babel/helper-function-name@7.24.7': - resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} + /@babel/generator@7.25.6: + resolution: {integrity: sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.25.6 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + dev: true - '@babel/helper-hoist-variables@7.24.7': - resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} + /@babel/helper-compilation-targets@7.25.2: + resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.25.4 + '@babel/helper-validator-option': 7.24.8 + browserslist: 4.24.0 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true - '@babel/helper-module-imports@7.24.7': + /@babel/helper-module-imports@7.24.7: resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true - '@babel/helper-module-transforms@7.24.7': - resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==} + /@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2): + resolution: {integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true - '@babel/helper-simple-access@7.24.7': + /@babel/helper-simple-access@7.24.7: resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + dev: true - '@babel/helper-split-export-declaration@7.24.7': - resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.24.7': - resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.24.8': + /@babel/helper-string-parser@7.24.8: resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.24.7': + /@babel/helper-validator-identifier@7.24.7: resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.24.7': - resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==} + /@babel/helper-validator-option@7.24.8: + resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==} engines: {node: '>=6.9.0'} + dev: true - '@babel/helpers@7.24.7': - resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==} + /@babel/helpers@7.25.6: + resolution: {integrity: sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.25.0 + '@babel/types': 7.25.6 + dev: true - '@babel/highlight@7.24.7': + /@babel/highlight@7.24.7: resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.1.0 + dev: true - '@babel/parser@7.24.7': - resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/parser@7.25.3': - resolution: {integrity: sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==} + /@babel/parser@7.25.6: + resolution: {integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==} engines: {node: '>=6.0.0'} hasBin: true + dependencies: + '@babel/types': 7.25.6 - '@babel/standalone@7.24.7': - resolution: {integrity: sha512-QRIRMJ2KTeN+vt4l9OjYlxDVXEpcor1Z6V7OeYzeBOw6Q8ew9oMTHjzTx8s6ClsZO7wVf6JgTRutihatN6K0yA==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.24.7': - resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==} + /@babel/standalone@7.25.6: + resolution: {integrity: sha512-Kf2ZcZVqsKbtYhlA7sP0z5A3q5hmCVYMKMWRWNK/5OVwHIve3JY1djVRmIVAx8FMueLIfZGKQDIILK2w8zO4mg==} engines: {node: '>=6.9.0'} + dev: true - '@babel/traverse@7.24.7': - resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==} + /@babel/template@7.25.0: + resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.25.6 + '@babel/types': 7.25.6 + dev: true - '@babel/types@7.24.7': - resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} + /@babel/traverse@7.25.6: + resolution: {integrity: sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.6 + '@babel/parser': 7.25.6 + '@babel/template': 7.25.0 + '@babel/types': 7.25.6 + debug: 4.3.7 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true - '@babel/types@7.25.2': - resolution: {integrity: sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==} + /@babel/types@7.25.6: + resolution: {integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 - '@ctrl/tinycolor@3.6.1': + /@ctrl/tinycolor@3.6.1: resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} engines: {node: '>=10'} + dev: false - '@element-plus/icons-vue@2.3.1': + /@element-plus/icons-vue@2.3.1(vue@3.5.9): resolution: {integrity: sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==} peerDependencies: vue: ^3.2.0 + dependencies: + vue: 3.5.9(typescript@5.6.2) + dev: false - '@esbuild/android-arm64@0.18.20': + /@esbuild/android-arm64@0.18.20: resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} cpu: [arm64] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-arm@0.18.20': + /@esbuild/android-arm@0.18.20: resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} engines: {node: '>=12'} cpu: [arm] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/android-x64@0.18.20': + /@esbuild/android-x64@0.18.20: resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} engines: {node: '>=12'} cpu: [x64] os: [android] + requiresBuild: true + dev: true + optional: true - '@esbuild/darwin-arm64@0.18.20': + /@esbuild/darwin-arm64@0.18.20: resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@esbuild/darwin-x64@0.18.20': + /@esbuild/darwin-x64@0.18.20: resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} engines: {node: '>=12'} cpu: [x64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@esbuild/freebsd-arm64@0.18.20': + /@esbuild/freebsd-arm64@0.18.20: resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/freebsd-x64@0.18.20': + /@esbuild/freebsd-x64@0.18.20: resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-arm64@0.18.20': + /@esbuild/linux-arm64@0.18.20: resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} engines: {node: '>=12'} cpu: [arm64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-arm@0.18.20': + /@esbuild/linux-arm@0.18.20: resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} engines: {node: '>=12'} cpu: [arm] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-ia32@0.18.20': + /@esbuild/linux-ia32@0.18.20: resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} engines: {node: '>=12'} cpu: [ia32] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-loong64@0.18.20': + /@esbuild/linux-loong64@0.18.20: resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-mips64el@0.18.20': + /@esbuild/linux-mips64el@0.18.20: resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-ppc64@0.18.20': + /@esbuild/linux-ppc64@0.18.20: resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-riscv64@0.18.20': + /@esbuild/linux-riscv64@0.18.20: resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-s390x@0.18.20': + /@esbuild/linux-s390x@0.18.20: resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} engines: {node: '>=12'} cpu: [s390x] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/linux-x64@0.18.20': + /@esbuild/linux-x64@0.18.20: resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} engines: {node: '>=12'} cpu: [x64] os: [linux] + requiresBuild: true + dev: true + optional: true - '@esbuild/netbsd-x64@0.18.20': + /@esbuild/netbsd-x64@0.18.20: resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/openbsd-x64@0.18.20': + /@esbuild/openbsd-x64@0.18.20: resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] + requiresBuild: true + dev: true + optional: true - '@esbuild/sunos-x64@0.18.20': + /@esbuild/sunos-x64@0.18.20: resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} engines: {node: '>=12'} cpu: [x64] os: [sunos] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-arm64@0.18.20': + /@esbuild/win32-arm64@0.18.20: resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} engines: {node: '>=12'} cpu: [arm64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-ia32@0.18.20': + /@esbuild/win32-ia32@0.18.20: resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} engines: {node: '>=12'} cpu: [ia32] os: [win32] + requiresBuild: true + dev: true + optional: true - '@esbuild/win32-x64@0.18.20': + /@esbuild/win32-x64@0.18.20: resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} engines: {node: '>=12'} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@fastify/busboy@2.1.1': + /@fastify/busboy@2.1.1: resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} + dev: true - '@floating-ui/core@1.6.2': - resolution: {integrity: sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==} + /@floating-ui/core@1.6.8: + resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==} + dependencies: + '@floating-ui/utils': 0.2.8 + dev: false - '@floating-ui/dom@1.6.5': - resolution: {integrity: sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==} + /@floating-ui/dom@1.6.11: + resolution: {integrity: sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==} + dependencies: + '@floating-ui/core': 1.6.8 + '@floating-ui/utils': 0.2.8 + dev: false - '@floating-ui/utils@0.2.2': - resolution: {integrity: sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==} + /@floating-ui/utils@0.2.8: + resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==} + dev: false - '@intlify/core-base@9.13.1': - resolution: {integrity: sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w==} + /@intlify/core-base@9.14.1: + resolution: {integrity: sha512-rG5/hlNW6Qfve41go37szEf0mVLcfhYuOu83JcY0jZKasnwsrcZYYWDzebCcuO5I/6Sy1JFWo9p+nvkQS1Dy+w==} engines: {node: '>= 16'} + dependencies: + '@intlify/message-compiler': 9.14.1 + '@intlify/shared': 9.14.1 + dev: false - '@intlify/message-compiler@9.13.1': - resolution: {integrity: sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w==} + /@intlify/message-compiler@9.14.1: + resolution: {integrity: sha512-MY8hwukJBnXvGAncVKlHsqKDQ5ZcQx4peqEmI8wBUTXn4pezrtTGYXNoz81cLyEEHB+L/zlKWVBSh5TiX4gYoQ==} engines: {node: '>= 16'} + dependencies: + '@intlify/shared': 9.14.1 + source-map-js: 1.2.1 + dev: false - '@intlify/shared@9.13.1': - resolution: {integrity: sha512-u3b6BKGhE6j/JeRU6C/RL2FgyJfy6LakbtfeVF8fJXURpZZTzfh3e05J0bu0XPw447Q6/WUp3C4ajv4TMS4YsQ==} + /@intlify/shared@9.14.1: + resolution: {integrity: sha512-XjHu6PEQup9MnP1x0W9y0nXXfq9jFftAYSfV11hryjtH4XqXP8HrzMvXI+ZVifF+jZLszaTzIhvukllplxTQTg==} engines: {node: '>= 16'} + dev: false - '@jridgewell/gen-mapping@0.3.5': + /@jridgewell/gen-mapping@0.3.5: resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + dev: true - '@jridgewell/resolve-uri@3.1.2': + /@jridgewell/resolve-uri@3.1.2: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + dev: true - '@jridgewell/set-array@1.2.1': + /@jridgewell/set-array@1.2.1: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} + dev: true - '@jridgewell/sourcemap-codec@1.4.15': - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - - '@jridgewell/sourcemap-codec@1.5.0': + /@jridgewell/sourcemap-codec@1.5.0: resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@jridgewell/trace-mapping@0.3.25': + /@jridgewell/trace-mapping@0.3.25: resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + dev: true - '@nodelib/fs.scandir@2.1.5': + /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true - '@nodelib/fs.stat@2.0.5': + /@nodelib/fs.stat@2.0.5: resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} + dev: true - '@nodelib/fs.walk@1.2.8': + /@nodelib/fs.walk@1.2.8: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + dev: true - '@nuxt/kit@3.11.2': - resolution: {integrity: sha512-yiYKP0ZWMW7T3TCmsv4H8+jEsB/nFriRAR8bKoSqSV9bkVYWPE36sf7JDux30dQ91jSlQG6LQkB3vCHYTS2cIg==} - engines: {node: ^14.18.0 || >=16.10.0} - - '@nuxt/kit@3.12.4': - resolution: {integrity: sha512-aNRD1ylzijY0oYolldNcZJXVyxdGzNTl+Xd0UYyFQCu9f4wqUZqQ9l+b7arCEzchr96pMK0xdpvLcS3xo1wDcw==} - engines: {node: ^14.18.0 || >=16.10.0} - - '@nuxt/schema@3.11.2': - resolution: {integrity: sha512-Z0bx7N08itD5edtpkstImLctWMNvxTArsKXzS35ZuqyAyKBPcRjO1CU01slH0ahO30Gg9kbck3/RKNZPwfOjJg==} + /@nuxt/kit@3.13.2: + resolution: {integrity: sha512-KvRw21zU//wdz25IeE1E5m/aFSzhJloBRAQtv+evcFeZvuroIxpIQuUqhbzuwznaUwpiWbmwlcsp5uOWmi4vwA==} engines: {node: ^14.18.0 || >=16.10.0} + dependencies: + '@nuxt/schema': 3.13.2 + c12: 1.11.2 + consola: 3.2.3 + defu: 6.1.4 + destr: 2.0.3 + globby: 14.0.2 + hash-sum: 2.0.0 + ignore: 5.3.2 + jiti: 1.21.6 + klona: 2.0.6 + knitwork: 1.1.0 + mlly: 1.7.1 + pathe: 1.1.2 + pkg-types: 1.2.0 + scule: 1.3.0 + semver: 7.6.3 + ufo: 1.5.4 + unctx: 2.3.1 + unimport: 3.13.0 + untyped: 1.5.0 + transitivePeerDependencies: + - magicast + - rollup + - supports-color + - webpack-sources + dev: true - '@nuxt/schema@3.12.4': - resolution: {integrity: sha512-H7FwBV4ChssMaeiLyPdVLOLUa0326ebp3pNbJfGgFt7rSoKh1MmgjorecA8JMxOQZziy3w6EELf4+5cgLh/F1w==} + /@nuxt/schema@3.13.2: + resolution: {integrity: sha512-CCZgpm+MkqtOMDEgF9SWgGPBXlQ01hV/6+2reDEpJuqFPGzV8HYKPBcIFvn7/z5ahtgutHLzjP71Na+hYcqSpw==} engines: {node: ^14.18.0 || >=16.10.0} + dependencies: + compatx: 0.1.8 + consola: 3.2.3 + defu: 6.1.4 + hookable: 5.5.3 + pathe: 1.1.2 + pkg-types: 1.2.0 + scule: 1.3.0 + std-env: 3.7.0 + ufo: 1.5.4 + uncrypto: 0.1.3 + unimport: 3.13.0 + untyped: 1.5.0 + transitivePeerDependencies: + - rollup + - supports-color + - webpack-sources + dev: true - '@nuxt/ui-templates@1.3.4': - resolution: {integrity: sha512-zjuslnkj5zboZGis5QpmR5gvRTx5N8Ha/Rll+RRT8YZhXVNBincifhZ9apUQ9f6T0xJE8IHPyVyPx6WokomdYw==} - - '@octokit/auth-token@2.5.0': + /@octokit/auth-token@2.5.0: resolution: {integrity: sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==} + dependencies: + '@octokit/types': 6.41.0 + dev: true - '@octokit/core@3.6.0': + /@octokit/core@3.6.0: resolution: {integrity: sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==} + dependencies: + '@octokit/auth-token': 2.5.0 + '@octokit/graphql': 4.8.0 + '@octokit/request': 5.6.3 + '@octokit/request-error': 2.1.0 + '@octokit/types': 6.41.0 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.1 + transitivePeerDependencies: + - encoding + dev: true - '@octokit/endpoint@6.0.12': + /@octokit/endpoint@6.0.12: resolution: {integrity: sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==} + dependencies: + '@octokit/types': 6.41.0 + is-plain-object: 5.0.0 + universal-user-agent: 6.0.1 + dev: true - '@octokit/graphql@4.8.0': + /@octokit/graphql@4.8.0: resolution: {integrity: sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==} + dependencies: + '@octokit/request': 5.6.3 + '@octokit/types': 6.41.0 + universal-user-agent: 6.0.1 + transitivePeerDependencies: + - encoding + dev: true - '@octokit/openapi-types@12.11.0': + /@octokit/openapi-types@12.11.0: resolution: {integrity: sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==} + dev: true - '@octokit/plugin-paginate-rest@2.21.3': + /@octokit/plugin-paginate-rest@2.21.3(@octokit/core@3.6.0): resolution: {integrity: sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==} peerDependencies: '@octokit/core': '>=2' + dependencies: + '@octokit/core': 3.6.0 + '@octokit/types': 6.41.0 + dev: true - '@octokit/plugin-rest-endpoint-methods@5.16.2': + /@octokit/plugin-rest-endpoint-methods@5.16.2(@octokit/core@3.6.0): resolution: {integrity: sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==} peerDependencies: '@octokit/core': '>=3' + dependencies: + '@octokit/core': 3.6.0 + '@octokit/types': 6.41.0 + deprecation: 2.3.1 + dev: true - '@octokit/request-error@2.1.0': + /@octokit/request-error@2.1.0: resolution: {integrity: sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==} + dependencies: + '@octokit/types': 6.41.0 + deprecation: 2.3.1 + once: 1.4.0 + dev: true - '@octokit/request@5.6.3': + /@octokit/request@5.6.3: resolution: {integrity: sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==} + dependencies: + '@octokit/endpoint': 6.0.12 + '@octokit/request-error': 2.1.0 + '@octokit/types': 6.41.0 + is-plain-object: 5.0.0 + node-fetch: 2.7.0 + universal-user-agent: 6.0.1 + transitivePeerDependencies: + - encoding + dev: true - '@octokit/types@6.41.0': + /@octokit/types@6.41.0: resolution: {integrity: sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==} + dependencies: + '@octokit/openapi-types': 12.11.0 + dev: true - '@rollup/pluginutils@5.1.0': - resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} + /@rollup/pluginutils@5.1.2: + resolution: {integrity: sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true + dependencies: + '@types/estree': 1.0.6 + estree-walker: 2.0.2 + picomatch: 2.3.1 + dev: true - '@rollup/rollup-android-arm-eabi@4.21.0': - resolution: {integrity: sha512-WTWD8PfoSAJ+qL87lE7votj3syLavxunWhzCnx3XFxFiI/BA/r3X7MUM8dVrH8rb2r4AiO8jJsr3ZjdaftmnfA==} - cpu: [arm] - os: [android] + /@sindresorhus/merge-streams@2.3.0: + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + dev: true - '@rollup/rollup-android-arm64@4.21.0': - resolution: {integrity: sha512-a1sR2zSK1B4eYkiZu17ZUZhmUQcKjk2/j9Me2IDjk1GHW7LB5Z35LEzj9iJch6gtUfsnvZs1ZNyDW2oZSThrkA==} - cpu: [arm64] - os: [android] + /@sxzz/popperjs-es@2.11.7: + resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==} + dev: false - '@rollup/rollup-darwin-arm64@4.21.0': - resolution: {integrity: sha512-zOnKWLgDld/svhKO5PD9ozmL6roy5OQ5T4ThvdYZLpiOhEGY+dp2NwUmxK0Ld91LrbjrvtNAE0ERBwjqhZTRAA==} + /@tauri-apps/api@1.6.0: + resolution: {integrity: sha512-rqI++FWClU5I2UBp4HXFvl+sBWkdigBkxnpJDQUWttNyG7IZP4FwQGhTNL5EOw0vI8i6eSAJ5frLqO7n7jbJdg==} + engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'} + dev: false + + /@tauri-apps/cli-darwin-arm64@1.6.2: + resolution: {integrity: sha512-6mdRyf9DaLqlZvj8kZB09U3rwY+dOHSGzTZ7+GDg665GJb17f4cb30e8dExj6/aghcsOie9EGpgiURcDUvLNSQ==} + engines: {node: '>= 10'} cpu: [arm64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-darwin-x64@4.21.0': - resolution: {integrity: sha512-7doS8br0xAkg48SKE2QNtMSFPFUlRdw9+votl27MvT46vo44ATBmdZdGysOevNELmZlfd+NEa0UYOA8f01WSrg==} + /@tauri-apps/cli-darwin-x64@1.6.2: + resolution: {integrity: sha512-PLxZY5dn38H3R9VRmBN/l0ZDB5JFanCwlK4rmpzDQPPg3tQmbu5vjSCP6TVj5U6aLKsj79kFyULblPr5Dn9+vw==} + engines: {node: '>= 10'} cpu: [x64] os: [darwin] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.21.0': - resolution: {integrity: sha512-pWJsfQjNWNGsoCq53KjMtwdJDmh/6NubwQcz52aEwLEuvx08bzcy6tOUuawAOncPnxz/3siRtd8hiQ32G1y8VA==} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm-musleabihf@4.21.0': - resolution: {integrity: sha512-efRIANsz3UHZrnZXuEvxS9LoCOWMGD1rweciD6uJQIx2myN3a8Im1FafZBzh7zk1RJ6oKcR16dU3UPldaKd83w==} + /@tauri-apps/cli-linux-arm-gnueabihf@1.6.2: + resolution: {integrity: sha512-xnpj4BLeeGOh5I/ewCQlYJZwHH0CBNBN+4q8BNWNQ9MKkjN9ST366RmHRzl2ANNgWwijOPxyce7GiUmvuH8Atw==} + engines: {node: '>= 10'} cpu: [arm] os: [linux] - libc: [musl] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm64-gnu@4.21.0': - resolution: {integrity: sha512-ZrPhydkTVhyeGTW94WJ8pnl1uroqVHM3j3hjdquwAcWnmivjAwOYjTEAuEDeJvGX7xv3Z9GAvrBkEzCgHq9U1w==} + /@tauri-apps/cli-linux-arm64-gnu@1.6.2: + resolution: {integrity: sha512-uaiRE0vE2P+tdsCngfKt+7yKr3VZXIq/t3w01DzSdnBgHSp0zmRsRR4AhZt7ibvoEgA8GzBP+eSHJdFNZsTU9w==} + engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-arm64-musl@4.21.0': - resolution: {integrity: sha512-cfaupqd+UEFeURmqNP2eEvXqgbSox/LHOyN9/d2pSdV8xTrjdg3NgOFJCtc1vQ/jEke1qD0IejbBfxleBPHnPw==} + /@tauri-apps/cli-linux-arm64-musl@1.6.2: + resolution: {integrity: sha512-o9JunVrMrhqTBLrdvEbS64W0bo1dPm0lxX51Mx+6x9SmbDjlEWGgaAHC3iKLK9khd5Yu1uO1e+8TJltAcScvmw==} + engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.21.0': - resolution: {integrity: sha512-ZKPan1/RvAhrUylwBXC9t7B2hXdpb/ufeu22pG2psV7RN8roOfGurEghw1ySmX/CmDDHNTDDjY3lo9hRlgtaHg==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-riscv64-gnu@4.21.0': - resolution: {integrity: sha512-H1eRaCwd5E8eS8leiS+o/NqMdljkcb1d6r2h4fKSsCXQilLKArq6WS7XBLDu80Yz+nMqHVFDquwcVrQmGr28rg==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-s390x-gnu@4.21.0': - resolution: {integrity: sha512-zJ4hA+3b5tu8u7L58CCSI0A9N1vkfwPhWd/puGXwtZlsB5bTkwDNW/+JCU84+3QYmKpLi+XvHdmrlwUwDA6kqw==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-gnu@4.21.0': - resolution: {integrity: sha512-e2hrvElFIh6kW/UNBQK/kzqMNY5mO+67YtEh9OA65RM5IJXYTWiXjX6fjIiPaqOkBthYF1EqgiZ6OXKcQsM0hg==} + /@tauri-apps/cli-linux-x64-gnu@1.6.2: + resolution: {integrity: sha512-jL9f+o61DdQmNYKIt2Q3BA8YJ+hyC5+GdNxqDf7j5SoQ85j//YfUWbmp9ZgsPHVBxgSGZVvgGMNvf64Ykp0buQ==} + engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-linux-x64-musl@4.21.0': - resolution: {integrity: sha512-1vvmgDdUSebVGXWX2lIcgRebqfQSff0hMEkLJyakQ9JQUbLDkEaMsPTLOmyccyC6IJ/l3FZuJbmrBw/u0A0uCQ==} + /@tauri-apps/cli-linux-x64-musl@1.6.2: + resolution: {integrity: sha512-xsa4Pu9YMHKAX0J8pIoXfN/uhvAAAoECZDixDhWw8zi57VZ4QX28ycqolS+NscdD9NAGSgHk45MpBZWdvRtvjQ==} + engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-arm64-msvc@4.21.0': - resolution: {integrity: sha512-s5oFkZ/hFcrlAyBTONFY1TWndfyre1wOMwU+6KCpm/iatybvrRgmZVM+vCFwxmC5ZhdlgfE0N4XorsDpi7/4XQ==} + /@tauri-apps/cli-win32-arm64-msvc@1.6.2: + resolution: {integrity: sha512-eJtUOx2UFhJpCCkm5M5+4Co9JbjvgIHTdyS/hTSZfOEdT58CNEGVJXMA39FsSZXYoxYPE+9K7Km6haMozSmlxw==} + engines: {node: '>= 10'} cpu: [arm64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-ia32-msvc@4.21.0': - resolution: {integrity: sha512-G9+TEqRnAA6nbpqyUqgTiopmnfgnMkR3kMukFBDsiyy23LZvUCpiUwjTRx6ezYCjJODXrh52rBR9oXvm+Fp5wg==} + /@tauri-apps/cli-win32-ia32-msvc@1.6.2: + resolution: {integrity: sha512-9Jwx3PrhNw3VKOgPISRRXPkvoEAZP+7rFRHXIo49dvlHy2E/o9qpWi1IntE33HWeazP6KhvsCjvXB2Ai4eGooA==} + engines: {node: '>= 10'} cpu: [ia32] os: [win32] + requiresBuild: true + dev: true + optional: true - '@rollup/rollup-win32-x64-msvc@4.21.0': - resolution: {integrity: sha512-2jsCDZwtQvRhejHLfZ1JY6w6kEuEtfF9nzYsZxzSlNVKDX+DpsDJ+Rbjkm74nvg2rdx0gwBS+IMdvwJuq3S9pQ==} + /@tauri-apps/cli-win32-x64-msvc@1.6.2: + resolution: {integrity: sha512-5Z+ZjRFJE8MXghJe1UXvGephY5ZcgVhiTI9yuMi9xgX3CEaAXASatyXllzsvGJ9EDaWMEpa0PHjAzi7LBAWROw==} + engines: {node: '>= 10'} cpu: [x64] os: [win32] + requiresBuild: true + dev: true + optional: true - '@sindresorhus/merge-streams@2.3.0': - resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} - engines: {node: '>=18'} - - '@sxzz/popperjs-es@2.11.7': - resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==} - - '@tauri-apps/api@1.5.6': - resolution: {integrity: sha512-LH5ToovAHnDVe5Qa9f/+jW28I6DeMhos8bNDtBOmmnaDpPmJmYLyHdeDblAWWWYc7KKRDg9/66vMuKyq0WIeFA==} - engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'} - - '@tauri-apps/cli-darwin-arm64@1.5.14': - resolution: {integrity: sha512-lxoSOp3KKSqzHJa7iT32dukPGMlfsTuja1xXSgwR8o/fqzpYJY7FY/3ZxesP8HR66FcK+vtqa//HNqeOQ0mHkA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@tauri-apps/cli-darwin-x64@1.5.14': - resolution: {integrity: sha512-EXSwN1n5spfG8FoXuyc90ACtmDJXzaZ1gxyENaq9xEpQoo7j/Q1vb6qXxmr6azKr8zmqY4h08ZFbv3exh93xJg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@tauri-apps/cli-linux-arm-gnueabihf@1.5.14': - resolution: {integrity: sha512-Yb8BH/KYR7Tl+de40sZPfrqbhcU3Jlu+UPIrnXt05sjn48xqIps74Xjz8zzVp0TuHxUp8FmIGtCVhQgsbrsvvg==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - - '@tauri-apps/cli-linux-arm64-gnu@1.5.14': - resolution: {integrity: sha512-QrKHP4gRaHiup478rPBZ+BmNd88yze9jMmheoNy9mN1K/aECRmTHO+tWhsxv5moFHZzRhO0QDWxxvTtiaPXaGg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@tauri-apps/cli-linux-arm64-musl@1.5.14': - resolution: {integrity: sha512-Hb1C1VMxmUcyGjW/K/INKF87zzzgLEVRmWZZnQd7M1P4uue4xPyIwUELSdX12Z2jREPgmLW4AXPD0m6wsNu7iw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@tauri-apps/cli-linux-x64-gnu@1.5.14': - resolution: {integrity: sha512-kD9v/UwPDuhIgq2TJj/s2/7rqk+vmExVV6xHPKI8vVbIvlNAOZqmx3fpxjej1241vhJ/piGd/m6q6YMWGsL0oQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@tauri-apps/cli-linux-x64-musl@1.5.14': - resolution: {integrity: sha512-204Drgg9Zx0+THKndqASz4+iPCwqA3gQVF9C0CDIArNXrjPyJjVvW8VP5CHiZYaTNWxlz/ltyxluM6UFWbXNFw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@tauri-apps/cli-win32-arm64-msvc@1.5.14': - resolution: {integrity: sha512-sqPSni2MnWNCm+8YZnLdWCclxfSHaYqKuPFSz8q7Tn1G1m/cA9gyPoC1G0esHftY7bu/ZM5lB4kM3I4U0KlLiA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@tauri-apps/cli-win32-ia32-msvc@1.5.14': - resolution: {integrity: sha512-8xN8W0zTs8oFsQmvYLxHFeqhzVI7oTaPK1xQMc5gbpFP45jN41c21aCXfjnvzT+h90EfCHUF9EWj2HTEJSb7Iw==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - - '@tauri-apps/cli-win32-x64-msvc@1.5.14': - resolution: {integrity: sha512-U0slee5tNM2PYECBpPHavLSwkT3szGMZ+qhcikQQbDan84bQdLn/kHWjyXOgLJs4KSve4+KxcrN+AVqj0VyHnw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@tauri-apps/cli@1.5.14': - resolution: {integrity: sha512-JOSMKymlg116UdEXSj69eg5p1OtZnQkUE0qIGbtNDO1sk3X/KgBN6+oHBW0BzPStp/W0AjBgrMWCqjHPwEpOug==} + /@tauri-apps/cli@1.6.2: + resolution: {integrity: sha512-zpfZdxhm20s7d/Uejpg/T3a9sqLVe3Ih2ztINfy8v6iLw9Ohowkb9g+agZffYKlEWfOSpmCy69NFyBLj7OZL0A==} engines: {node: '>= 10'} hasBin: true - - '@types/estree@1.0.5': - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - - '@types/lodash-es@4.17.12': + optionalDependencies: + '@tauri-apps/cli-darwin-arm64': 1.6.2 + '@tauri-apps/cli-darwin-x64': 1.6.2 + '@tauri-apps/cli-linux-arm-gnueabihf': 1.6.2 + '@tauri-apps/cli-linux-arm64-gnu': 1.6.2 + '@tauri-apps/cli-linux-arm64-musl': 1.6.2 + '@tauri-apps/cli-linux-x64-gnu': 1.6.2 + '@tauri-apps/cli-linux-x64-musl': 1.6.2 + '@tauri-apps/cli-win32-arm64-msvc': 1.6.2 + '@tauri-apps/cli-win32-ia32-msvc': 1.6.2 + '@tauri-apps/cli-win32-x64-msvc': 1.6.2 + dev: true + + /@types/estree@1.0.6: + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + dev: true + + /@types/lodash-es@4.17.12: resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} + dependencies: + '@types/lodash': 4.17.9 + dev: false - '@types/lodash@4.17.4': - resolution: {integrity: sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ==} + /@types/lodash@4.17.9: + resolution: {integrity: sha512-w9iWudx1XWOHW5lQRS9iKpK/XuRhnN+0T7HvdCCd802FYkT1AMTnxndJHGrNJwRoRHkslGr4S29tjm1cT7x/7w==} + dev: false - '@types/node@18.19.34': - resolution: {integrity: sha512-eXF4pfBNV5DAMKGbI02NnDtWrQ40hAN558/2vvS4gMpMIxaf6JmD7YjnZbq0Q9TDSSkKBamime8ewRoomHdt4g==} + /@types/node@18.19.53: + resolution: {integrity: sha512-GLxgUgHhDKO1Edw9Q0lvMbiO/IQXJwJlMaqxSGBXMpPy8uhkCs2iiPFaB2Q/gmobnFkckD3rqTBMVjXdwq+nKg==} + dependencies: + undici-types: 5.26.5 + dev: true - '@types/uuid@9.0.8': + /@types/uuid@9.0.8: resolution: {integrity: sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==} + dev: true - '@types/web-bluetooth@0.0.16': + /@types/web-bluetooth@0.0.16: resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} + dev: false - '@types/web-bluetooth@0.0.20': + /@types/web-bluetooth@0.0.20: resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} - '@vitejs/plugin-vue@4.6.2': + /@vitejs/plugin-vue@4.6.2(vite@4.5.5)(vue@3.5.9): resolution: {integrity: sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^4.0.0 || ^5.0.0 vue: ^3.2.25 + dependencies: + vite: 4.5.5(@types/node@18.19.53) + vue: 3.5.9(typescript@5.6.2) + dev: true - '@volar/language-core@2.4.0': - resolution: {integrity: sha512-FTla+khE+sYK0qJP+6hwPAAUwiNHVMph4RUXpxf/FIPKUP61NFrVZorml4mjFShnueR2y9/j8/vnh09YwVdH7A==} - - '@volar/source-map@2.4.0': - resolution: {integrity: sha512-2ceY8/NEZvN6F44TXw2qRP6AQsvCYhV2bxaBPWxV9HqIfkbRydSksTFObCF1DBDNBfKiZTS8G/4vqV6cvjdOIQ==} - - '@volar/typescript@2.4.0': - resolution: {integrity: sha512-9zx3lQWgHmVd+JRRAHUSRiEhe4TlzL7U7e6ulWXOxHH/WNYxzKwCvZD7WYWEZFdw4dHfTD9vUR0yPQO6GilCaQ==} + /@volar/language-core@2.4.5: + resolution: {integrity: sha512-F4tA0DCO5Q1F5mScHmca0umsi2ufKULAnMOVBfMsZdT4myhVl4WdKRwCaKcfOkIEuyrAVvtq1ESBdZ+rSyLVww==} + dependencies: + '@volar/source-map': 2.4.5 + dev: true - '@vue/compiler-core@3.4.27': - resolution: {integrity: sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==} + /@volar/source-map@2.4.5: + resolution: {integrity: sha512-varwD7RaKE2J/Z+Zu6j3mNNJbNT394qIxXwdvz/4ao/vxOfyClZpSDtLKkwWmecinkOVos5+PWkWraelfMLfpw==} + dev: true - '@vue/compiler-core@3.4.38': - resolution: {integrity: sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==} + /@volar/typescript@2.4.5: + resolution: {integrity: sha512-mcT1mHvLljAEtHviVcBuOyAwwMKz1ibXTi5uYtP/pf4XxoAzpdkQ+Br2IC0NPCvLCbjPZmbf3I0udndkfB1CDg==} + dependencies: + '@volar/language-core': 2.4.5 + path-browserify: 1.0.1 + vscode-uri: 3.0.8 + dev: true - '@vue/compiler-dom@3.4.27': - resolution: {integrity: sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==} + /@vue/compiler-core@3.5.9: + resolution: {integrity: sha512-KE1sCdwqSKq0CQ/ltg3XnlMTKeinjegIkuFsuq9DKvNPmqLGdmI51ChZdGBBRXIvEYTLm8X/JxOuBQ1HqF/+PA==} + dependencies: + '@babel/parser': 7.25.6 + '@vue/shared': 3.5.9 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 - '@vue/compiler-dom@3.4.38': - resolution: {integrity: sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==} + /@vue/compiler-dom@3.5.9: + resolution: {integrity: sha512-gEAURwPo902AsJF50vl59VaWR+Cx6cX9SoqLYHu1jq9hDbmQlXvpZyYNIIbxa2JTJ+FD/oBQweVUwuTQv79KTg==} + dependencies: + '@vue/compiler-core': 3.5.9 + '@vue/shared': 3.5.9 - '@vue/compiler-sfc@3.4.27': - resolution: {integrity: sha512-nDwntUEADssW8e0rrmE0+OrONwmRlegDA1pD6QhVeXxjIytV03yDqTey9SBDiALsvAd5U4ZrEKbMyVXhX6mCGA==} + /@vue/compiler-sfc@3.5.9: + resolution: {integrity: sha512-kp9qawcTXakYm0TN6YAwH24IurSywoXh4fWhRbLu0at4UVyo994bhEzJlQn82eiyqtut4GjkQodSfn8drFbpZQ==} + dependencies: + '@babel/parser': 7.25.6 + '@vue/compiler-core': 3.5.9 + '@vue/compiler-dom': 3.5.9 + '@vue/compiler-ssr': 3.5.9 + '@vue/shared': 3.5.9 + estree-walker: 2.0.2 + magic-string: 0.30.11 + postcss: 8.4.47 + source-map-js: 1.2.1 - '@vue/compiler-ssr@3.4.27': - resolution: {integrity: sha512-CVRzSJIltzMG5FcidsW0jKNQnNRYC8bT21VegyMMtHmhW3UOI7knmUehzswXLrExDLE6lQCZdrhD4ogI7c+vuw==} + /@vue/compiler-ssr@3.5.9: + resolution: {integrity: sha512-fb1g2mQv32QzIei76rlXRTz08Grw+ZzBXSQfHo4StGFutm/flyebw3dGJkexKwcU3GjX9s5fIGjEv/cjO8j8Yw==} + dependencies: + '@vue/compiler-dom': 3.5.9 + '@vue/shared': 3.5.9 - '@vue/compiler-vue2@2.7.16': + /@vue/compiler-vue2@2.7.16: resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + dev: true - '@vue/devtools-api@6.6.3': - resolution: {integrity: sha512-0MiMsFma/HqA6g3KLKn+AGpL1kgKhFWszC9U29NfpWK5LE7bjeXxySWJrOJ77hBz+TBrBQ7o4QJqbPbqbs8rJw==} + /@vue/devtools-api@6.6.4: + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + dev: false - '@vue/language-core@2.0.29': - resolution: {integrity: sha512-o2qz9JPjhdoVj8D2+9bDXbaI4q2uZTHQA/dbyZT4Bj1FR9viZxDJnLcKVHfxdn6wsOzRgpqIzJEEmSSvgMvDTQ==} + /@vue/language-core@2.1.6(typescript@5.6.2): + resolution: {integrity: sha512-MW569cSky9R/ooKMh6xa2g1D0AtRKbL56k83dzus/bx//RDJk24RHWkMzbAlXjMdDNyxAaagKPRquBIxkxlCkg==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true + dependencies: + '@volar/language-core': 2.4.5 + '@vue/compiler-dom': 3.5.9 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.9 + computeds: 0.0.1 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + typescript: 5.6.2 + dev: true - '@vue/reactivity@3.4.27': - resolution: {integrity: sha512-kK0g4NknW6JX2yySLpsm2jlunZJl2/RJGZ0H9ddHdfBVHcNzxmQ0sS0b09ipmBoQpY8JM2KmUw+a6sO8Zo+zIA==} + /@vue/reactivity@3.5.9: + resolution: {integrity: sha512-88ApgNZ6yPYpyYkTfXzcbWk6O8+LrPRIpa/U4AdeTzpfRUO+EUt5jemnTBVSlAUNmlYY96xa5feUNEq+BouLog==} + dependencies: + '@vue/shared': 3.5.9 - '@vue/runtime-core@3.4.27': - resolution: {integrity: sha512-7aYA9GEbOOdviqVvcuweTLe5Za4qBZkUY7SvET6vE8kyypxVgaT1ixHLg4urtOlrApdgcdgHoTZCUuTGap/5WA==} + /@vue/runtime-core@3.5.9: + resolution: {integrity: sha512-YAeP0zNkjSl5mEc1NxOg9qoAhLNbREElHAhfYbMXT57oF0ixehEEJWBhg2uvVxslCGh23JhpEAyMvJrJHW9WGg==} + dependencies: + '@vue/reactivity': 3.5.9 + '@vue/shared': 3.5.9 - '@vue/runtime-dom@3.4.27': - resolution: {integrity: sha512-ScOmP70/3NPM+TW9hvVAz6VWWtZJqkbdf7w6ySsws+EsqtHvkhxaWLecrTorFxsawelM5Ys9FnDEMt6BPBDS0Q==} + /@vue/runtime-dom@3.5.9: + resolution: {integrity: sha512-5Oq/5oenpB9lw94moKvOHqBDEaMSyDmcu2HS8AtAT6/pwdo/t9fR9aVtLh6FzYGGqZR9yRfoHAN6P7goblq1aA==} + dependencies: + '@vue/reactivity': 3.5.9 + '@vue/runtime-core': 3.5.9 + '@vue/shared': 3.5.9 + csstype: 3.1.3 - '@vue/server-renderer@3.4.27': - resolution: {integrity: sha512-dlAMEuvmeA3rJsOMJ2J1kXU7o7pOxgsNHVr9K8hB3ImIkSuBrIdy0vF66h8gf8Tuinf1TK3mPAz2+2sqyf3KzA==} + /@vue/server-renderer@3.5.9(vue@3.5.9): + resolution: {integrity: sha512-tbuUsZfMWGazR9LXLNiiDSTwkO8K9sLyR70diY+FbQmKmh7236PPz4jkTxymelV8D89IJUGtbfe4VdmpHkmuxg==} peerDependencies: - vue: 3.4.27 - - '@vue/shared@3.4.27': - resolution: {integrity: sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==} + vue: 3.5.9 + dependencies: + '@vue/compiler-ssr': 3.5.9 + '@vue/shared': 3.5.9 + vue: 3.5.9(typescript@5.6.2) - '@vue/shared@3.4.38': - resolution: {integrity: sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==} + /@vue/shared@3.5.9: + resolution: {integrity: sha512-8wiT/m0mnsLhTME0mPgc57jv+4TipRBSAAmheUdYgiOaO6AobZPNOmm87ub4np65VVDgLcWxc+Edc++5Wyz1uA==} - '@vueuse/core@10.10.0': - resolution: {integrity: sha512-vexJ/YXYs2S42B783rI95lMt3GzEwkxzC8Hb0Ndpd8rD+p+Lk/Za4bd797Ym7yq4jXqdSyj3JLChunF/vyYjUw==} + /@vueuse/core@10.11.1(vue@3.5.9): + resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==} + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 10.11.1 + '@vueuse/shared': 10.11.1(vue@3.5.9) + vue-demi: 0.14.10(vue@3.5.9) + transitivePeerDependencies: + - '@vue/composition-api' + - vue - '@vueuse/core@9.13.0': + /@vueuse/core@9.13.0(vue@3.5.9): resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==} + dependencies: + '@types/web-bluetooth': 0.0.16 + '@vueuse/metadata': 9.13.0 + '@vueuse/shared': 9.13.0(vue@3.5.9) + vue-demi: 0.14.10(vue@3.5.9) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false - '@vueuse/metadata@10.10.0': - resolution: {integrity: sha512-UNAo2sTCAW5ge6OErPEHb5z7NEAg3XcO9Cj7OK45aZXfLLH1QkexDcZD77HBi5zvEiLOm1An+p/4b5K3Worpug==} + /@vueuse/metadata@10.11.1: + resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==} - '@vueuse/metadata@9.13.0': + /@vueuse/metadata@9.13.0: resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==} + dev: false - '@vueuse/shared@10.10.0': - resolution: {integrity: sha512-2aW33Ac0Uk0U+9yo3Ypg9s5KcR42cuehRWl7vnUHadQyFvCktseyxxEPBi1Eiq4D2yBGACOnqLZpx1eMc7g5Og==} + /@vueuse/shared@10.11.1(vue@3.5.9): + resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==} + dependencies: + vue-demi: 0.14.10(vue@3.5.9) + transitivePeerDependencies: + - '@vue/composition-api' + - vue - '@vueuse/shared@9.13.0': + /@vueuse/shared@9.13.0(vue@3.5.9): resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==} + dependencies: + vue-demi: 0.14.10(vue@3.5.9) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false - acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true - - acorn@8.12.1: + /acorn@8.12.1: resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} engines: {node: '>=0.4.0'} hasBin: true + dev: true - adm-zip@0.5.14: - resolution: {integrity: sha512-DnyqqifT4Jrcvb8USYjp6FHtBpEIz1mnXu6pTRHZ0RL69LbQYiO+0lDFg5+OKA7U29oWSs3a/i8fhn8ZcceIWg==} + /adm-zip@0.5.16: + resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} engines: {node: '>=12.0'} + dev: true - ansi-styles@3.2.1: + /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: true - anymatch@3.1.3: + /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true - async-validator@4.2.5: + /async-validator@4.2.5: resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==} + dev: false - balanced-match@1.0.2: + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true - before-after-hook@2.2.3: + /before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + dev: true - binary-extensions@2.3.0: + /binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + dev: true - brace-expansion@2.0.1: + /brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true - braces@3.0.3: + /braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + dependencies: + fill-range: 7.1.1 + dev: true - browserslist@4.23.0: - resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + /browserslist@4.24.0: + resolution: {integrity: sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + dependencies: + caniuse-lite: 1.0.30001664 + electron-to-chromium: 1.5.29 + node-releases: 2.0.18 + update-browserslist-db: 1.1.1(browserslist@4.24.0) + dev: true - c12@1.10.0: - resolution: {integrity: sha512-0SsG7UDhoRWcuSvKWHaXmu5uNjDCDN3nkQLRL4Q42IlFy+ze58FcCoI3uPwINXinkz7ZinbhEgyzYFw9u9ZV8g==} - - c12@1.11.1: - resolution: {integrity: sha512-KDU0TvSvVdaYcQKQ6iPHATGz/7p/KiVjPg4vQrB6Jg/wX9R0yl5RZxWm9IoZqaIHD2+6PZd81+KMGwRr/lRIUg==} + /c12@1.11.2: + resolution: {integrity: sha512-oBs8a4uvSDO9dm8b7OCFW7+dgtVrwmwnrVXYzLm43ta7ep2jCn/0MhoUFygIWtxhyy6+/MG7/agvpY0U1Iemew==} peerDependencies: magicast: ^0.3.4 peerDependenciesMeta: magicast: optional: true + dependencies: + chokidar: 3.6.0 + confbox: 0.1.7 + defu: 6.1.4 + dotenv: 16.4.5 + giget: 1.2.3 + jiti: 1.21.6 + mlly: 1.7.1 + ohash: 1.1.4 + pathe: 1.1.2 + perfect-debounce: 1.0.0 + pkg-types: 1.2.0 + rc9: 2.1.2 + dev: true - caniuse-lite@1.0.30001629: - resolution: {integrity: sha512-c3dl911slnQhmxUIT4HhYzT7wnBK/XYpGnYLOj4nJBaRiw52Ibe7YxlDaAeRECvA786zCuExhxIUJ2K7nHMrBw==} + /caniuse-lite@1.0.30001664: + resolution: {integrity: sha512-AmE7k4dXiNKQipgn7a2xg558IRqPN3jMQY/rOsbxDhrd0tyChwbITBfiwtnqz8bi2M5mIWbxAYBvk7W7QBUS2g==} + dev: true - chalk@2.4.2: + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: true - chokidar@3.6.0: + /chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true - chownr@2.0.0: + /chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} + dev: true - citty@0.1.6: + /citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + dependencies: + consola: 3.2.3 + dev: true - color-convert@1.9.3: + /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: true - color-name@1.1.3: + /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: true - compatx@0.1.8: + /compatx@0.1.8: resolution: {integrity: sha512-jcbsEAR81Bt5s1qOFymBufmCbXCXbk0Ql+K5ouj6gCyx2yHlu6AgmGIi9HxfKixpUDO5bCFJUHQ5uM6ecbTebw==} + dev: true - computeds@0.0.1: + /computeds@0.0.1: resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==} + dev: true - confbox@0.1.7: + /confbox@0.1.7: resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} + dev: true - consola@3.2.3: + /consola@3.2.3: resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} engines: {node: ^14.18.0 || >=16.10.0} + dev: true - convert-source-map@2.0.0: + /convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true - cross-spawn@7.0.3: + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true - csstype@3.1.3: + /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - dayjs@1.11.11: - resolution: {integrity: sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==} + /dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + dev: false - de-indent@1.0.2: + /de-indent@1.0.2: resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + dev: true - debug@4.3.5: - resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + /debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true + dependencies: + ms: 2.1.3 + dev: true - defu@6.1.4: + /defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + dev: true - deprecation@2.3.1: + /deprecation@2.3.1: resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + dev: true - destr@2.0.3: + /destr@2.0.3: resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==} + dev: true - dotenv@16.4.5: + /dotenv@16.4.5: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} + dev: true - electron-to-chromium@1.4.792: - resolution: {integrity: sha512-rkg5/N3L+Y844JyfgPUyuKK0Hk0efo3JNxUDKvz3HgP6EmN4rNGhr2D8boLsfTV/hGo7ZGAL8djw+jlg99zQyA==} + /electron-to-chromium@1.5.29: + resolution: {integrity: sha512-PF8n2AlIhCKXQ+gTpiJi0VhcHDb69kYX4MtCiivctc2QD3XuNZ/XIOlbGzt7WAjjEev0TtaH6Cu3arZExm5DOw==} + dev: true - element-plus@2.7.4: - resolution: {integrity: sha512-ADBN3zHdhg8R9m6IXR2B5txSWvCn1+nAD+aA9kaJ4rZHMr37DVX6EOdwUjqAMPKz2xC0tculgkJ5rh5zVNiDNQ==} + /element-plus@2.8.3(vue@3.5.9): + resolution: {integrity: sha512-BXQOyDf0s7JHyNEV8iaO+iaOzTZPsBXVKMzMI967vLCodUBDLrtiY5vglAn1YEebQcUOEUMhGcttTpIvEkcBjQ==} peerDependencies: vue: ^3.2.0 + dependencies: + '@ctrl/tinycolor': 3.6.1 + '@element-plus/icons-vue': 2.3.1(vue@3.5.9) + '@floating-ui/dom': 1.6.11 + '@popperjs/core': /@sxzz/popperjs-es@2.11.7 + '@types/lodash': 4.17.9 + '@types/lodash-es': 4.17.12 + '@vueuse/core': 9.13.0(vue@3.5.9) + async-validator: 4.2.5 + dayjs: 1.11.13 + escape-html: 1.0.3 + lodash: 4.17.21 + lodash-es: 4.17.21 + lodash-unified: 1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21) + memoize-one: 6.0.0 + normalize-wheel-es: 1.2.0 + vue: 3.5.9(typescript@5.6.2) + transitivePeerDependencies: + - '@vue/composition-api' + dev: false - entities@4.5.0: + /entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} - esbuild@0.18.20: + /esbuild@0.18.20: resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} engines: {node: '>=12'} hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true - escalade@3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + /escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + dev: true - escape-html@1.0.3: + /escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + dev: false - escape-string-regexp@1.0.5: + /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} + dev: true - escape-string-regexp@5.0.0: + /escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} + dev: true - estree-walker@2.0.2: + /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - estree-walker@3.0.3: + /estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + dependencies: + '@types/estree': 1.0.6 + dev: true - execa@8.0.1: + /execa@8.0.1: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + dev: true - fast-glob@3.3.2: + /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + dev: true - fastq@1.17.1: + /fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + dependencies: + reusify: 1.0.4 + dev: true - fill-range@7.1.1: + /fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true - fs-extra@10.1.0: + /fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true - fs-minipass@2.1.0: + /fs-minipass@2.1.0: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + dev: true - fsevents@2.3.3: + /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + requiresBuild: true + dev: true + optional: true - function-bind@1.1.2: + /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true - gensync@1.0.0-beta.2: + /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + dev: true - get-stream@8.0.1: + /get-stream@8.0.1: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} + dev: true - giget@1.2.3: + /giget@1.2.3: resolution: {integrity: sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA==} hasBin: true + dependencies: + citty: 0.1.6 + consola: 3.2.3 + defu: 6.1.4 + node-fetch-native: 1.6.4 + nypm: 0.3.12 + ohash: 1.1.4 + pathe: 1.1.2 + tar: 6.2.1 + dev: true - glob-parent@5.1.2: + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true - globals@11.12.0: + /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} + dev: true - globby@14.0.1: - resolution: {integrity: sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==} - engines: {node: '>=18'} - - globby@14.0.2: + /globby@14.0.2: resolution: {integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==} engines: {node: '>=18'} + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.2 + ignore: 5.3.2 + path-type: 5.0.0 + slash: 5.1.0 + unicorn-magic: 0.1.0 + dev: true - graceful-fs@4.2.11: + /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: true - has-flag@3.0.0: + /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} + dev: true - hash-sum@2.0.0: + /hash-sum@2.0.0: resolution: {integrity: sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==} + dev: true - hasown@2.0.2: + /hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true - he@1.2.0: + /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true + dev: true - hookable@5.5.3: + /hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + dev: true - human-signals@5.0.0: + /human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} + dev: true - ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} - engines: {node: '>= 4'} - - ignore@5.3.2: + /ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + dev: true - is-binary-path@2.1.0: + /is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} + dependencies: + binary-extensions: 2.3.0 + dev: true - is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + /is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + dependencies: + hasown: 2.0.2 + dev: true - is-extglob@2.1.1: + /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + dev: true - is-glob@4.0.3: + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true - is-number@7.0.0: + /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + dev: true - is-plain-object@5.0.0: + /is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} + dev: true - is-stream@3.0.0: + /is-stream@3.0.0: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true - isexe@2.0.0: + /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true - jiti@1.21.3: - resolution: {integrity: sha512-uy2bNX5zQ+tESe+TiC7ilGRz8AtRGmnJH55NC5S0nSUjvvvM2hJHmefHErugGXN4pNv4Qx7vLsnNw9qJ9mtIsw==} + /jiti@1.21.6: + resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} hasBin: true + dev: true - jiti@1.21.6: - resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} + /jiti@2.0.0: + resolution: {integrity: sha512-CJ7e7Abb779OTRv3lomfp7Mns/Sy1+U4pcAx5VbjxCZD5ZM/VJaXPpPjNKjtSvWQy/H86E49REXR34dl1JEz9w==} hasBin: true + dev: true - js-tokens@4.0.0: + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true - js-tokens@9.0.0: + /js-tokens@9.0.0: resolution: {integrity: sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==} + dev: true - jsesc@2.5.2: + /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} hasBin: true + dev: true - json5@2.2.3: + /json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true + dev: true - jsonfile@6.1.0: + /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + dev: true - klona@2.0.6: + /klona@2.0.6: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} + dev: true - knitwork@1.1.0: + /knitwork@1.1.0: resolution: {integrity: sha512-oHnmiBUVHz1V+URE77PNot2lv3QiYU2zQf1JjOVkMt3YDKGbu8NAFr+c4mcNOhdsGrB/VpVbRwPwhiXrPhxQbw==} + dev: true - local-pkg@0.4.3: + /local-pkg@0.4.3: resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} engines: {node: '>=14'} + dev: true - local-pkg@0.5.0: + /local-pkg@0.5.0: resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} engines: {node: '>=14'} + dependencies: + mlly: 1.7.1 + pkg-types: 1.2.0 + dev: true - lodash-es@4.17.21: + /lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + dev: false - lodash-unified@1.0.3: + /lodash-unified@1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21): resolution: {integrity: sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==} peerDependencies: '@types/lodash-es': '*' lodash: '*' lodash-es: '*' + dependencies: + '@types/lodash-es': 4.17.12 + lodash: 4.17.21 + lodash-es: 4.17.21 + dev: false - lodash@4.17.21: + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false - lru-cache@5.1.1: + /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true - magic-string@0.27.0: + /magic-string@0.27.0: resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + dev: true - magic-string@0.29.0: + /magic-string@0.29.0: resolution: {integrity: sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q==} engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + dev: true - magic-string@0.30.10: - resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} - - magic-string@0.30.11: + /magic-string@0.30.11: resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 - memoize-one@6.0.0: + /memoize-one@6.0.0: resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} + dev: false - merge-stream@2.0.0: + /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true - merge2@1.4.1: + /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + dev: true - micromatch@4.0.7: - resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + /micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + dev: true - mimic-fn@4.0.0: + /mimic-fn@4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + dev: true - minimatch@7.4.6: + /minimatch@7.4.6: resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true - minimatch@9.0.5: + /minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true - minipass@3.3.6: + /minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} + dependencies: + yallist: 4.0.0 + dev: true - minipass@5.0.0: + /minipass@5.0.0: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} + dev: true - minizlib@2.1.2: + /minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + dev: true - mkdirp@1.0.4: + /mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true + dev: true - mlly@1.7.1: + /mlly@1.7.1: resolution: {integrity: sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==} + dependencies: + acorn: 8.12.1 + pathe: 1.1.2 + pkg-types: 1.2.0 + ufo: 1.5.4 + dev: true - mri@1.2.0: + /mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} + dev: true - ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true - muggle-string@0.4.1: + /muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + dev: true - nanoid@3.3.7: + /nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - node-fetch-native@1.6.4: + /node-fetch-native@1.6.4: resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} + dev: true - node-fetch@2.7.0: + /node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} peerDependencies: @@ -1169,69 +1767,101 @@ packages: peerDependenciesMeta: encoding: optional: true + dependencies: + whatwg-url: 5.0.0 + dev: true - node-releases@2.0.14: - resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + /node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + dev: true - normalize-path@3.0.0: + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + dev: true - normalize-wheel-es@1.2.0: + /normalize-wheel-es@1.2.0: resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==} + dev: false - npm-run-path@5.3.0: + /npm-run-path@5.3.0: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + path-key: 4.0.0 + dev: true - nypm@0.3.8: - resolution: {integrity: sha512-IGWlC6So2xv6V4cIDmoV0SwwWx7zLG086gyqkyumteH2fIgCAM4nDVFB2iDRszDvmdSVW9xb1N+2KjQ6C7d4og==} + /nypm@0.3.12: + resolution: {integrity: sha512-D3pzNDWIvgA+7IORhD/IuWzEk4uXv6GsgOxiid4UU3h9oq5IqV1KtPDi63n4sZJ/xcWlr88c0QM2RgN5VbOhFA==} engines: {node: ^14.16.0 || >=16.10.0} hasBin: true + dependencies: + citty: 0.1.6 + consola: 3.2.3 + execa: 8.0.1 + pathe: 1.1.2 + pkg-types: 1.2.0 + ufo: 1.5.4 + dev: true - ohash@1.1.3: - resolution: {integrity: sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==} + /ohash@1.1.4: + resolution: {integrity: sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g==} + dev: true - once@1.4.0: + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: true - onetime@6.0.0: + /onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} + dependencies: + mimic-fn: 4.0.0 + dev: true - path-browserify@1.0.1: + /path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: true - path-key@3.1.1: + /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + dev: true - path-key@4.0.0: + /path-key@4.0.0: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} engines: {node: '>=12'} + dev: true - path-parse@1.0.7: + /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true - path-type@5.0.0: + /path-type@5.0.0: resolution: {integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==} engines: {node: '>=12'} + dev: true - pathe@1.1.2: + /pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + dev: true - perfect-debounce@1.0.0: + /perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + dev: true - picocolors@1.0.1: - resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + /picocolors@1.1.0: + resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} - picomatch@2.3.1: + /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + dev: true - pinia@2.1.7: - resolution: {integrity: sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==} + /pinia@2.2.2(typescript@5.6.2)(vue@3.5.9): + resolution: {integrity: sha512-ja2XqFWZC36mupU4z1ZzxeTApV7DOw44cV4dhQ9sGwun+N89v/XP7+j7q6TanS1u1tdbK4r+1BUx7heMaIdagA==} peerDependencies: '@vue/composition-api': ^1.4.0 typescript: '>=4.4.4' @@ -1241,173 +1871,275 @@ packages: optional: true typescript: optional: true + dependencies: + '@vue/devtools-api': 6.6.4 + typescript: 5.6.2 + vue: 3.5.9(typescript@5.6.2) + vue-demi: 0.14.10(vue@3.5.9) + dev: false - pkg-types@1.1.1: - resolution: {integrity: sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==} - - pkg-types@1.1.3: - resolution: {integrity: sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA==} + /pkg-types@1.2.0: + resolution: {integrity: sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==} + dependencies: + confbox: 0.1.7 + mlly: 1.7.1 + pathe: 1.1.2 + dev: true - postcss@8.4.38: - resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} + /postcss@8.4.47: + resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.1.0 + source-map-js: 1.2.1 - queue-microtask@1.2.3: + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true - rc9@2.1.2: + /rc9@2.1.2: resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + dependencies: + defu: 6.1.4 + destr: 2.0.3 + dev: true - readdirp@3.6.0: + /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true - resolve@1.22.8: + /resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true + dependencies: + is-core-module: 2.15.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true - reusify@1.0.4: + /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true - rollup@3.29.4: - resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} + /rollup@3.29.5: + resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true - rollup@4.21.0: - resolution: {integrity: sha512-vo+S/lfA2lMS7rZ2Qoubi6I5hwZwzXeUIctILZLbHI+laNtvhhOIon2S1JksA5UEDQ7l3vberd0fxK44lTYjbQ==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - run-parallel@1.2.0: + /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true - scule@1.3.0: + /scule@1.3.0: resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + dev: true - semver@6.3.1: + /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + dev: true - semver@7.6.2: - resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} - engines: {node: '>=10'} - hasBin: true - - semver@7.6.3: + /semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} hasBin: true + dev: true - shebang-command@2.0.0: + /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true - shebang-regex@3.0.0: + /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + dev: true - signal-exit@4.1.0: + /signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + dev: true - slash@5.1.0: + /slash@5.1.0: resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} engines: {node: '>=14.16'} + dev: true - sortablejs@1.14.0: + /sortablejs@1.14.0: resolution: {integrity: sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==} + dev: false - source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + /source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - std-env@3.7.0: + /std-env@3.7.0: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + dev: true - strip-final-newline@3.0.0: + /strip-final-newline@3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} + dev: true - strip-literal@1.3.0: + /strip-literal@1.3.0: resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==} + dependencies: + acorn: 8.12.1 + dev: true - strip-literal@2.1.0: + /strip-literal@2.1.0: resolution: {integrity: sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==} + dependencies: + js-tokens: 9.0.0 + dev: true - supports-color@5.5.0: + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: true - supports-preserve-symlinks-flag@1.0.0: + /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + dev: true - tar@6.2.1: + /tar@6.2.1: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + dev: true - to-fast-properties@2.0.0: + /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} - to-regex-range@5.0.1: + /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true - tr46@0.0.3: + /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: true - tunnel@0.0.6: + /tunnel@0.0.6: resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + dev: true - typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + /typescript@5.6.2: + resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} engines: {node: '>=14.17'} hasBin: true - ufo@1.5.3: - resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} - - ufo@1.5.4: + /ufo@1.5.4: resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + dev: true - uncrypto@0.1.3: + /uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + dev: true - unctx@2.3.1: + /unctx@2.3.1: resolution: {integrity: sha512-PhKke8ZYauiqh3FEMVNm7ljvzQiph0Mt3GBRve03IJm7ukfaON2OBK795tLwhbyfzknuRRkW0+Ze+CQUmzOZ+A==} + dependencies: + acorn: 8.12.1 + estree-walker: 3.0.3 + magic-string: 0.30.11 + unplugin: 1.14.1 + transitivePeerDependencies: + - webpack-sources + dev: true - undici-types@5.26.5: + /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true - undici@5.28.4: + /undici@5.28.4: resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} engines: {node: '>=14.0'} + dependencies: + '@fastify/busboy': 2.1.1 + dev: true - unicorn-magic@0.1.0: + /unicorn-magic@0.1.0: resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} engines: {node: '>=18'} + dev: true - unimport@2.2.4: + /unimport@2.2.4: resolution: {integrity: sha512-qMgmeEGqqrrmEtm0dqxMG37J6xBtrriqxq9hILvDb+e6l2F0yTnJomLoCCp0eghLR7bYGeBsUU5Y0oyiUYhViw==} + dependencies: + '@rollup/pluginutils': 5.1.2 + escape-string-regexp: 5.0.0 + fast-glob: 3.3.2 + local-pkg: 0.4.3 + magic-string: 0.27.0 + mlly: 1.7.1 + pathe: 1.1.2 + pkg-types: 1.2.0 + scule: 1.3.0 + strip-literal: 1.3.0 + unplugin: 1.14.1 + transitivePeerDependencies: + - rollup + - webpack-sources + dev: true - unimport@3.10.0: - resolution: {integrity: sha512-/UvKRfWx3mNDWwWQhR62HsoM3wxHwYdTq8ellZzMOHnnw4Dp8tovgthyW7DjTrbjDL+i4idOp06voz2VKlvrLw==} - - unimport@3.7.2: - resolution: {integrity: sha512-91mxcZTadgXyj3lFWmrGT8GyoRHWuE5fqPOjg5RVtF6vj+OfM5G6WCzXjuYtSgELE5ggB34RY4oiCSEP8I3AHw==} + /unimport@3.13.0: + resolution: {integrity: sha512-0WkKsLy8jkcnB38VQdAGvF0N2trJyDbUuHsfXcyrspwgwWTIThiMpvnDNZMVsuNc11SwT2GYzcQ2RnI1TY/xcw==} + dependencies: + '@rollup/pluginutils': 5.1.2 + acorn: 8.12.1 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + fast-glob: 3.3.2 + local-pkg: 0.5.0 + magic-string: 0.30.11 + mlly: 1.7.1 + pathe: 1.1.2 + pkg-types: 1.2.0 + scule: 1.3.0 + strip-literal: 2.1.0 + unplugin: 1.14.1 + transitivePeerDependencies: + - rollup + - webpack-sources + dev: true - universal-user-agent@6.0.1: + /universal-user-agent@6.0.1: resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} + dev: true - universalify@2.0.1: + /universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + dev: true - unplugin-auto-import@0.14.4: + /unplugin-auto-import@0.14.4(@vueuse/core@10.11.1): resolution: {integrity: sha512-3vlaVhJ2B/Ct31F8X7tAiGpfPIr8bYhX/VVF6FB+1RkOfi61oh1zMmd3NTjwaEwkr6GV+J6BfvQL9NQ193V0sw==} engines: {node: '>=14'} peerDependencies: @@ -1415,8 +2147,24 @@ packages: peerDependenciesMeta: '@vueuse/core': optional: true + dependencies: + '@antfu/utils': 0.7.10 + '@nuxt/kit': 3.13.2 + '@rollup/pluginutils': 5.1.2 + '@vueuse/core': 10.11.1(vue@3.5.9) + local-pkg: 0.4.3 + magic-string: 0.29.0 + minimatch: 7.4.6 + unimport: 2.2.4 + unplugin: 1.14.1 + transitivePeerDependencies: + - magicast + - rollup + - supports-color + - webpack-sources + dev: true - unplugin-vue-components@0.24.1: + /unplugin-vue-components@0.24.1(vue@3.5.9): resolution: {integrity: sha512-T3A8HkZoIE1Cja95xNqolwza0yD5IVlgZZ1PVAGvVCx8xthmjsv38xWRCtHtwl+rvZyL9uif42SRkDGw9aCfMA==} engines: {node: '>=14'} peerDependencies: @@ -1428,31 +2176,70 @@ packages: optional: true '@nuxt/kit': optional: true + dependencies: + '@antfu/utils': 0.7.10 + '@rollup/pluginutils': 5.1.2 + chokidar: 3.6.0 + debug: 4.3.7 + fast-glob: 3.3.2 + local-pkg: 0.4.3 + magic-string: 0.30.11 + minimatch: 7.4.6 + resolve: 1.22.8 + unplugin: 1.14.1 + vue: 3.5.9(typescript@5.6.2) + transitivePeerDependencies: + - rollup + - supports-color + - webpack-sources + dev: true - unplugin@1.10.1: - resolution: {integrity: sha512-d6Mhq8RJeGA8UfKCu54Um4lFA0eSaRa3XxdAJg8tIdxbu1ubW0hBCZUL7yI2uGyYCRndvbK8FLHzqy2XKfeMsg==} - engines: {node: '>=14.0.0'} - - unplugin@1.12.2: - resolution: {integrity: sha512-bEqQxeC7rxtxPZ3M5V4Djcc4lQqKPgGe3mAWZvxcSmX5jhGxll19NliaRzQSQPrk4xJZSGniK3puLWpRuZN7VQ==} + /unplugin@1.14.1: + resolution: {integrity: sha512-lBlHbfSFPToDYp9pjXlUEFVxYLaue9f9T1HC+4OHlmj+HnMDdz9oZY+erXfoCe/5V/7gKUSY2jpXPb9S7f0f/w==} engines: {node: '>=14.0.0'} + peerDependencies: + webpack-sources: ^3 + peerDependenciesMeta: + webpack-sources: + optional: true + dependencies: + acorn: 8.12.1 + webpack-virtual-modules: 0.6.2 + dev: true - untyped@1.4.2: - resolution: {integrity: sha512-nC5q0DnPEPVURPhfPQLahhSTnemVtPzdx7ofiRxXpOB2SYnb3MfdU3DVGyJdS8Lx+tBWeAePO8BfU/3EgksM7Q==} + /untyped@1.5.0: + resolution: {integrity: sha512-o2Vjmn2dal08BzCcINxSmWuAteReUUiXseii5VRhmxyLF0b21K0iKZQ9fMYK7RWspVkY+0saqaVQNq4roe3Efg==} hasBin: true + dependencies: + '@babel/core': 7.25.2 + '@babel/standalone': 7.25.6 + '@babel/types': 7.25.6 + defu: 6.1.4 + jiti: 2.0.0 + mri: 1.2.0 + scule: 1.3.0 + transitivePeerDependencies: + - supports-color + dev: true - update-browserslist-db@1.0.16: - resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} + /update-browserslist-db@1.1.1(browserslist@4.24.0): + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.24.0 + escalade: 3.2.0 + picocolors: 1.1.0 + dev: true - uuid@9.0.1: + /uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true + dev: false - vite@4.5.3: - resolution: {integrity: sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==} + /vite@4.5.5(@types/node@18.19.53): + resolution: {integrity: sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: @@ -1478,1642 +2265,121 @@ packages: optional: true terser: optional: true + dependencies: + '@types/node': 18.19.53 + esbuild: 0.18.20 + postcss: 8.4.47 + rollup: 3.29.5 + optionalDependencies: + fsevents: 2.3.3 + dev: true - vscode-uri@3.0.8: + /vscode-uri@3.0.8: resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + dev: true - vue-demi@0.14.8: - resolution: {integrity: sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==} + /vue-demi@0.14.10(vue@3.5.9): + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} engines: {node: '>=12'} hasBin: true + requiresBuild: true peerDependencies: '@vue/composition-api': ^1.0.0-rc.1 vue: ^3.0.0-0 || ^2.6.0 peerDependenciesMeta: '@vue/composition-api': optional: true + dependencies: + vue: 3.5.9(typescript@5.6.2) - vue-i18n@9.13.1: - resolution: {integrity: sha512-mh0GIxx0wPtPlcB1q4k277y0iKgo25xmDPWioVVYanjPufDBpvu5ySTjP5wOrSvlYQ2m1xI+CFhGdauv/61uQg==} + /vue-i18n@9.14.1(vue@3.5.9): + resolution: {integrity: sha512-xjxV0LYc1xQ8TbAVfIyZiOSS8qoU1R0YwV7V5I8I6Fd64+zvsTsdPgtylPsie3Vdt9wekeYhr+smKDeaK6RBuA==} engines: {node: '>= 16'} peerDependencies: vue: ^3.0.0 + dependencies: + '@intlify/core-base': 9.14.1 + '@intlify/shared': 9.14.1 + '@vue/devtools-api': 6.6.4 + vue: 3.5.9(typescript@5.6.2) + dev: false - vue-router@4.3.2: - resolution: {integrity: sha512-hKQJ1vDAZ5LVkKEnHhmm1f9pMiWIBNGF5AwU67PdH7TyXCj/a4hTccuUuYCAMgJK6rO/NVYtQIEN3yL8CECa7Q==} + /vue-router@4.4.5(vue@3.5.9): + resolution: {integrity: sha512-4fKZygS8cH1yCyuabAXGUAsyi1b2/o/OKgu/RUb+znIYOxPRxdkytJEx+0wGcpBE1pX6vUgh5jwWOKRGvuA/7Q==} peerDependencies: vue: ^3.2.0 + dependencies: + '@vue/devtools-api': 6.6.4 + vue: 3.5.9(typescript@5.6.2) + dev: false - vue-tsc@2.0.29: - resolution: {integrity: sha512-MHhsfyxO3mYShZCGYNziSbc63x7cQ5g9kvijV7dRe1TTXBRLxXyL0FnXWpUF1xII2mJ86mwYpYsUmMwkmerq7Q==} + /vue-tsc@2.1.6(typescript@5.6.2): + resolution: {integrity: sha512-f98dyZp5FOukcYmbFpuSCJ4Z0vHSOSmxGttZJCsFeX0M4w/Rsq0s4uKXjcSRsZqsRgQa6z7SfuO+y0HVICE57Q==} hasBin: true peerDependencies: typescript: '>=5.0.0' + dependencies: + '@volar/typescript': 2.4.5 + '@vue/language-core': 2.1.6(typescript@5.6.2) + semver: 7.6.3 + typescript: 5.6.2 + dev: true - vue@3.4.27: - resolution: {integrity: sha512-8s/56uK6r01r1icG/aEOHqyMVxd1bkYcSe9j8HcKtr/xTOFWvnzIVTehNW+5Yt89f+DLBe4A569pnZLS5HzAMA==} + /vue@3.5.9(typescript@5.6.2): + resolution: {integrity: sha512-nHzQhZ5cjFKynAY2beAm7XtJ5C13VKAFTLTgRYXy+Id1KEKBeiK6hO2RcW1hUjdbHMadz1YzxyHgQigOC54wug==} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true + dependencies: + '@vue/compiler-dom': 3.5.9 + '@vue/compiler-sfc': 3.5.9 + '@vue/runtime-dom': 3.5.9 + '@vue/server-renderer': 3.5.9(vue@3.5.9) + '@vue/shared': 3.5.9 + typescript: 5.6.2 - vuedraggable@4.1.0: + /vuedraggable@4.1.0(vue@3.5.9): resolution: {integrity: sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==} peerDependencies: vue: ^3.0.1 + dependencies: + sortablejs: 1.14.0 + vue: 3.5.9(typescript@5.6.2) + dev: false - webidl-conversions@3.0.1: + /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: true - webpack-sources@3.2.3: - resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} - engines: {node: '>=10.13.0'} - - webpack-virtual-modules@0.6.2: + /webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + dev: true - whatwg-url@5.0.0: + /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: true - which@2.0.2: + /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true + dependencies: + isexe: 2.0.0 + dev: true - wrappy@1.0.2: + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true - yallist@3.1.1: + /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true - yallist@4.0.0: + /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - -snapshots: - - '@actions/github@5.1.1': - dependencies: - '@actions/http-client': 2.2.1 - '@octokit/core': 3.6.0 - '@octokit/plugin-paginate-rest': 2.21.3(@octokit/core@3.6.0) - '@octokit/plugin-rest-endpoint-methods': 5.16.2(@octokit/core@3.6.0) - transitivePeerDependencies: - - encoding - - '@actions/http-client@2.2.1': - dependencies: - tunnel: 0.0.6 - undici: 5.28.4 - - '@ampproject/remapping@2.3.0': - dependencies: - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 - - '@antfu/utils@0.7.8': {} - - '@babel/code-frame@7.24.7': - dependencies: - '@babel/highlight': 7.24.7 - picocolors: 1.0.1 - - '@babel/compat-data@7.24.7': {} - - '@babel/core@7.24.7': - dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.24.7 - '@babel/generator': 7.24.7 - '@babel/helper-compilation-targets': 7.24.7 - '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) - '@babel/helpers': 7.24.7 - '@babel/parser': 7.24.7 - '@babel/template': 7.24.7 - '@babel/traverse': 7.24.7 - '@babel/types': 7.24.7 - convert-source-map: 2.0.0 - debug: 4.3.5 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.24.7': - dependencies: - '@babel/types': 7.24.7 - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 - jsesc: 2.5.2 - - '@babel/helper-compilation-targets@7.24.7': - dependencies: - '@babel/compat-data': 7.24.7 - '@babel/helper-validator-option': 7.24.7 - browserslist: 4.23.0 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-environment-visitor@7.24.7': - dependencies: - '@babel/types': 7.24.7 - - '@babel/helper-function-name@7.24.7': - dependencies: - '@babel/template': 7.24.7 - '@babel/types': 7.24.7 - - '@babel/helper-hoist-variables@7.24.7': - dependencies: - '@babel/types': 7.24.7 - - '@babel/helper-module-imports@7.24.7': - dependencies: - '@babel/traverse': 7.24.7 - '@babel/types': 7.24.7 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7)': - dependencies: - '@babel/core': 7.24.7 - '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-module-imports': 7.24.7 - '@babel/helper-simple-access': 7.24.7 - '@babel/helper-split-export-declaration': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 - transitivePeerDependencies: - - supports-color - - '@babel/helper-simple-access@7.24.7': - dependencies: - '@babel/traverse': 7.24.7 - '@babel/types': 7.24.7 - transitivePeerDependencies: - - supports-color - - '@babel/helper-split-export-declaration@7.24.7': - dependencies: - '@babel/types': 7.24.7 - - '@babel/helper-string-parser@7.24.7': {} - - '@babel/helper-string-parser@7.24.8': {} - - '@babel/helper-validator-identifier@7.24.7': {} - - '@babel/helper-validator-option@7.24.7': {} - - '@babel/helpers@7.24.7': - dependencies: - '@babel/template': 7.24.7 - '@babel/types': 7.24.7 - - '@babel/highlight@7.24.7': - dependencies: - '@babel/helper-validator-identifier': 7.24.7 - chalk: 2.4.2 - js-tokens: 4.0.0 - picocolors: 1.0.1 - - '@babel/parser@7.24.7': - dependencies: - '@babel/types': 7.24.7 - - '@babel/parser@7.25.3': - dependencies: - '@babel/types': 7.25.2 - - '@babel/standalone@7.24.7': {} - - '@babel/template@7.24.7': - dependencies: - '@babel/code-frame': 7.24.7 - '@babel/parser': 7.24.7 - '@babel/types': 7.24.7 - - '@babel/traverse@7.24.7': - dependencies: - '@babel/code-frame': 7.24.7 - '@babel/generator': 7.24.7 - '@babel/helper-environment-visitor': 7.24.7 - '@babel/helper-function-name': 7.24.7 - '@babel/helper-hoist-variables': 7.24.7 - '@babel/helper-split-export-declaration': 7.24.7 - '@babel/parser': 7.24.7 - '@babel/types': 7.24.7 - debug: 4.3.5 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.24.7': - dependencies: - '@babel/helper-string-parser': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 - to-fast-properties: 2.0.0 - - '@babel/types@7.25.2': - dependencies: - '@babel/helper-string-parser': 7.24.8 - '@babel/helper-validator-identifier': 7.24.7 - to-fast-properties: 2.0.0 - - '@ctrl/tinycolor@3.6.1': {} - - '@element-plus/icons-vue@2.3.1(vue@3.4.27(typescript@5.4.5))': - dependencies: - vue: 3.4.27(typescript@5.4.5) - - '@esbuild/android-arm64@0.18.20': - optional: true - - '@esbuild/android-arm@0.18.20': - optional: true - - '@esbuild/android-x64@0.18.20': - optional: true - - '@esbuild/darwin-arm64@0.18.20': - optional: true - - '@esbuild/darwin-x64@0.18.20': - optional: true - - '@esbuild/freebsd-arm64@0.18.20': - optional: true - - '@esbuild/freebsd-x64@0.18.20': - optional: true - - '@esbuild/linux-arm64@0.18.20': - optional: true - - '@esbuild/linux-arm@0.18.20': - optional: true - - '@esbuild/linux-ia32@0.18.20': - optional: true - - '@esbuild/linux-loong64@0.18.20': - optional: true - - '@esbuild/linux-mips64el@0.18.20': - optional: true - - '@esbuild/linux-ppc64@0.18.20': - optional: true - - '@esbuild/linux-riscv64@0.18.20': - optional: true - - '@esbuild/linux-s390x@0.18.20': - optional: true - - '@esbuild/linux-x64@0.18.20': - optional: true - - '@esbuild/netbsd-x64@0.18.20': - optional: true - - '@esbuild/openbsd-x64@0.18.20': - optional: true - - '@esbuild/sunos-x64@0.18.20': - optional: true - - '@esbuild/win32-arm64@0.18.20': - optional: true - - '@esbuild/win32-ia32@0.18.20': - optional: true - - '@esbuild/win32-x64@0.18.20': - optional: true - - '@fastify/busboy@2.1.1': {} - - '@floating-ui/core@1.6.2': - dependencies: - '@floating-ui/utils': 0.2.2 - - '@floating-ui/dom@1.6.5': - dependencies: - '@floating-ui/core': 1.6.2 - '@floating-ui/utils': 0.2.2 - - '@floating-ui/utils@0.2.2': {} - - '@intlify/core-base@9.13.1': - dependencies: - '@intlify/message-compiler': 9.13.1 - '@intlify/shared': 9.13.1 - - '@intlify/message-compiler@9.13.1': - dependencies: - '@intlify/shared': 9.13.1 - source-map-js: 1.2.0 - - '@intlify/shared@9.13.1': {} - - '@jridgewell/gen-mapping@0.3.5': - dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.25 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/set-array@1.2.1': {} - - '@jridgewell/sourcemap-codec@1.4.15': {} - - '@jridgewell/sourcemap-codec@1.5.0': - optional: true - - '@jridgewell/trace-mapping@0.3.25': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 - - '@nuxt/kit@3.11.2(rollup@4.21.0)': - dependencies: - '@nuxt/schema': 3.11.2(rollup@4.21.0) - c12: 1.10.0 - consola: 3.2.3 - defu: 6.1.4 - globby: 14.0.1 - hash-sum: 2.0.0 - ignore: 5.3.1 - jiti: 1.21.3 - knitwork: 1.1.0 - mlly: 1.7.1 - pathe: 1.1.2 - pkg-types: 1.1.1 - scule: 1.3.0 - semver: 7.6.2 - ufo: 1.5.3 - unctx: 2.3.1 - unimport: 3.7.2(rollup@4.21.0) - untyped: 1.4.2 - transitivePeerDependencies: - - rollup - - supports-color - - '@nuxt/kit@3.12.4(rollup@4.21.0)': - dependencies: - '@nuxt/schema': 3.12.4(rollup@4.21.0) - c12: 1.11.1 - consola: 3.2.3 - defu: 6.1.4 - destr: 2.0.3 - globby: 14.0.2 - hash-sum: 2.0.0 - ignore: 5.3.2 - jiti: 1.21.6 - klona: 2.0.6 - knitwork: 1.1.0 - mlly: 1.7.1 - pathe: 1.1.2 - pkg-types: 1.1.3 - scule: 1.3.0 - semver: 7.6.3 - ufo: 1.5.4 - unctx: 2.3.1 - unimport: 3.10.0(rollup@4.21.0) - untyped: 1.4.2 - transitivePeerDependencies: - - magicast - - rollup - - supports-color - optional: true - - '@nuxt/schema@3.11.2(rollup@4.21.0)': - dependencies: - '@nuxt/ui-templates': 1.3.4 - consola: 3.2.3 - defu: 6.1.4 - hookable: 5.5.3 - pathe: 1.1.2 - pkg-types: 1.1.1 - scule: 1.3.0 - std-env: 3.7.0 - ufo: 1.5.3 - unimport: 3.7.2(rollup@4.21.0) - untyped: 1.4.2 - transitivePeerDependencies: - - rollup - - supports-color - - '@nuxt/schema@3.12.4(rollup@4.21.0)': - dependencies: - compatx: 0.1.8 - consola: 3.2.3 - defu: 6.1.4 - hookable: 5.5.3 - pathe: 1.1.2 - pkg-types: 1.1.3 - scule: 1.3.0 - std-env: 3.7.0 - ufo: 1.5.4 - uncrypto: 0.1.3 - unimport: 3.10.0(rollup@4.21.0) - untyped: 1.4.2 - transitivePeerDependencies: - - rollup - - supports-color - optional: true - - '@nuxt/ui-templates@1.3.4': {} - - '@octokit/auth-token@2.5.0': - dependencies: - '@octokit/types': 6.41.0 - - '@octokit/core@3.6.0': - dependencies: - '@octokit/auth-token': 2.5.0 - '@octokit/graphql': 4.8.0 - '@octokit/request': 5.6.3 - '@octokit/request-error': 2.1.0 - '@octokit/types': 6.41.0 - before-after-hook: 2.2.3 - universal-user-agent: 6.0.1 - transitivePeerDependencies: - - encoding - - '@octokit/endpoint@6.0.12': - dependencies: - '@octokit/types': 6.41.0 - is-plain-object: 5.0.0 - universal-user-agent: 6.0.1 - - '@octokit/graphql@4.8.0': - dependencies: - '@octokit/request': 5.6.3 - '@octokit/types': 6.41.0 - universal-user-agent: 6.0.1 - transitivePeerDependencies: - - encoding - - '@octokit/openapi-types@12.11.0': {} - - '@octokit/plugin-paginate-rest@2.21.3(@octokit/core@3.6.0)': - dependencies: - '@octokit/core': 3.6.0 - '@octokit/types': 6.41.0 - - '@octokit/plugin-rest-endpoint-methods@5.16.2(@octokit/core@3.6.0)': - dependencies: - '@octokit/core': 3.6.0 - '@octokit/types': 6.41.0 - deprecation: 2.3.1 - - '@octokit/request-error@2.1.0': - dependencies: - '@octokit/types': 6.41.0 - deprecation: 2.3.1 - once: 1.4.0 - - '@octokit/request@5.6.3': - dependencies: - '@octokit/endpoint': 6.0.12 - '@octokit/request-error': 2.1.0 - '@octokit/types': 6.41.0 - is-plain-object: 5.0.0 - node-fetch: 2.7.0 - universal-user-agent: 6.0.1 - transitivePeerDependencies: - - encoding - - '@octokit/types@6.41.0': - dependencies: - '@octokit/openapi-types': 12.11.0 - - '@rollup/pluginutils@5.1.0(rollup@4.21.0)': - dependencies: - '@types/estree': 1.0.5 - estree-walker: 2.0.2 - picomatch: 2.3.1 - optionalDependencies: - rollup: 4.21.0 - - '@rollup/rollup-android-arm-eabi@4.21.0': - optional: true - - '@rollup/rollup-android-arm64@4.21.0': - optional: true - - '@rollup/rollup-darwin-arm64@4.21.0': - optional: true - - '@rollup/rollup-darwin-x64@4.21.0': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.21.0': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.21.0': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.21.0': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.21.0': - optional: true - - '@rollup/rollup-linux-powerpc64le-gnu@4.21.0': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.21.0': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.21.0': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.21.0': - optional: true - - '@rollup/rollup-linux-x64-musl@4.21.0': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.21.0': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.21.0': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.21.0': - optional: true - - '@sindresorhus/merge-streams@2.3.0': {} - - '@sxzz/popperjs-es@2.11.7': {} - - '@tauri-apps/api@1.5.6': {} - - '@tauri-apps/cli-darwin-arm64@1.5.14': - optional: true - - '@tauri-apps/cli-darwin-x64@1.5.14': - optional: true - - '@tauri-apps/cli-linux-arm-gnueabihf@1.5.14': - optional: true - - '@tauri-apps/cli-linux-arm64-gnu@1.5.14': - optional: true - - '@tauri-apps/cli-linux-arm64-musl@1.5.14': - optional: true - - '@tauri-apps/cli-linux-x64-gnu@1.5.14': - optional: true - - '@tauri-apps/cli-linux-x64-musl@1.5.14': - optional: true - - '@tauri-apps/cli-win32-arm64-msvc@1.5.14': - optional: true - - '@tauri-apps/cli-win32-ia32-msvc@1.5.14': - optional: true - - '@tauri-apps/cli-win32-x64-msvc@1.5.14': - optional: true - - '@tauri-apps/cli@1.5.14': - optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 1.5.14 - '@tauri-apps/cli-darwin-x64': 1.5.14 - '@tauri-apps/cli-linux-arm-gnueabihf': 1.5.14 - '@tauri-apps/cli-linux-arm64-gnu': 1.5.14 - '@tauri-apps/cli-linux-arm64-musl': 1.5.14 - '@tauri-apps/cli-linux-x64-gnu': 1.5.14 - '@tauri-apps/cli-linux-x64-musl': 1.5.14 - '@tauri-apps/cli-win32-arm64-msvc': 1.5.14 - '@tauri-apps/cli-win32-ia32-msvc': 1.5.14 - '@tauri-apps/cli-win32-x64-msvc': 1.5.14 - - '@types/estree@1.0.5': {} - - '@types/lodash-es@4.17.12': - dependencies: - '@types/lodash': 4.17.4 - - '@types/lodash@4.17.4': {} - - '@types/node@18.19.34': - dependencies: - undici-types: 5.26.5 - - '@types/uuid@9.0.8': {} - - '@types/web-bluetooth@0.0.16': {} - - '@types/web-bluetooth@0.0.20': {} - - '@vitejs/plugin-vue@4.6.2(vite@4.5.3(@types/node@18.19.34))(vue@3.4.27(typescript@5.4.5))': - dependencies: - vite: 4.5.3(@types/node@18.19.34) - vue: 3.4.27(typescript@5.4.5) - - '@volar/language-core@2.4.0': - dependencies: - '@volar/source-map': 2.4.0 - - '@volar/source-map@2.4.0': {} - - '@volar/typescript@2.4.0': - dependencies: - '@volar/language-core': 2.4.0 - path-browserify: 1.0.1 - vscode-uri: 3.0.8 - - '@vue/compiler-core@3.4.27': - dependencies: - '@babel/parser': 7.24.7 - '@vue/shared': 3.4.27 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.2.0 - - '@vue/compiler-core@3.4.38': - dependencies: - '@babel/parser': 7.25.3 - '@vue/shared': 3.4.38 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.2.0 - - '@vue/compiler-dom@3.4.27': - dependencies: - '@vue/compiler-core': 3.4.27 - '@vue/shared': 3.4.27 - - '@vue/compiler-dom@3.4.38': - dependencies: - '@vue/compiler-core': 3.4.38 - '@vue/shared': 3.4.38 - - '@vue/compiler-sfc@3.4.27': - dependencies: - '@babel/parser': 7.24.7 - '@vue/compiler-core': 3.4.27 - '@vue/compiler-dom': 3.4.27 - '@vue/compiler-ssr': 3.4.27 - '@vue/shared': 3.4.27 - estree-walker: 2.0.2 - magic-string: 0.30.10 - postcss: 8.4.38 - source-map-js: 1.2.0 - - '@vue/compiler-ssr@3.4.27': - dependencies: - '@vue/compiler-dom': 3.4.27 - '@vue/shared': 3.4.27 - - '@vue/compiler-vue2@2.7.16': - dependencies: - de-indent: 1.0.2 - he: 1.2.0 - - '@vue/devtools-api@6.6.3': {} - - '@vue/language-core@2.0.29(typescript@5.4.5)': - dependencies: - '@volar/language-core': 2.4.0 - '@vue/compiler-dom': 3.4.38 - '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.4.38 - computeds: 0.0.1 - minimatch: 9.0.5 - muggle-string: 0.4.1 - path-browserify: 1.0.1 - optionalDependencies: - typescript: 5.4.5 - - '@vue/reactivity@3.4.27': - dependencies: - '@vue/shared': 3.4.27 - - '@vue/runtime-core@3.4.27': - dependencies: - '@vue/reactivity': 3.4.27 - '@vue/shared': 3.4.27 - - '@vue/runtime-dom@3.4.27': - dependencies: - '@vue/runtime-core': 3.4.27 - '@vue/shared': 3.4.27 - csstype: 3.1.3 - - '@vue/server-renderer@3.4.27(vue@3.4.27(typescript@5.4.5))': - dependencies: - '@vue/compiler-ssr': 3.4.27 - '@vue/shared': 3.4.27 - vue: 3.4.27(typescript@5.4.5) - - '@vue/shared@3.4.27': {} - - '@vue/shared@3.4.38': {} - - '@vueuse/core@10.10.0(vue@3.4.27(typescript@5.4.5))': - dependencies: - '@types/web-bluetooth': 0.0.20 - '@vueuse/metadata': 10.10.0 - '@vueuse/shared': 10.10.0(vue@3.4.27(typescript@5.4.5)) - vue-demi: 0.14.8(vue@3.4.27(typescript@5.4.5)) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - - '@vueuse/core@9.13.0(vue@3.4.27(typescript@5.4.5))': - dependencies: - '@types/web-bluetooth': 0.0.16 - '@vueuse/metadata': 9.13.0 - '@vueuse/shared': 9.13.0(vue@3.4.27(typescript@5.4.5)) - vue-demi: 0.14.8(vue@3.4.27(typescript@5.4.5)) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - - '@vueuse/metadata@10.10.0': {} - - '@vueuse/metadata@9.13.0': {} - - '@vueuse/shared@10.10.0(vue@3.4.27(typescript@5.4.5))': - dependencies: - vue-demi: 0.14.8(vue@3.4.27(typescript@5.4.5)) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - - '@vueuse/shared@9.13.0(vue@3.4.27(typescript@5.4.5))': - dependencies: - vue-demi: 0.14.8(vue@3.4.27(typescript@5.4.5)) - transitivePeerDependencies: - - '@vue/composition-api' - - vue - - acorn@8.11.3: {} - - acorn@8.12.1: - optional: true - - adm-zip@0.5.14: {} - - ansi-styles@3.2.1: - dependencies: - color-convert: 1.9.3 - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - - async-validator@4.2.5: {} - - balanced-match@1.0.2: {} - - before-after-hook@2.2.3: {} - - binary-extensions@2.3.0: {} - - brace-expansion@2.0.1: - dependencies: - balanced-match: 1.0.2 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.23.0: - dependencies: - caniuse-lite: 1.0.30001629 - electron-to-chromium: 1.4.792 - node-releases: 2.0.14 - update-browserslist-db: 1.0.16(browserslist@4.23.0) - - c12@1.10.0: - dependencies: - chokidar: 3.6.0 - confbox: 0.1.7 - defu: 6.1.4 - dotenv: 16.4.5 - giget: 1.2.3 - jiti: 1.21.3 - mlly: 1.7.1 - ohash: 1.1.3 - pathe: 1.1.2 - perfect-debounce: 1.0.0 - pkg-types: 1.1.1 - rc9: 2.1.2 - - c12@1.11.1: - dependencies: - chokidar: 3.6.0 - confbox: 0.1.7 - defu: 6.1.4 - dotenv: 16.4.5 - giget: 1.2.3 - jiti: 1.21.6 - mlly: 1.7.1 - ohash: 1.1.3 - pathe: 1.1.2 - perfect-debounce: 1.0.0 - pkg-types: 1.1.3 - rc9: 2.1.2 - optional: true - - caniuse-lite@1.0.30001629: {} - - chalk@2.4.2: - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - - chownr@2.0.0: {} - - citty@0.1.6: - dependencies: - consola: 3.2.3 - - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 - - color-name@1.1.3: {} - - compatx@0.1.8: - optional: true - - computeds@0.0.1: {} - - confbox@0.1.7: {} - - consola@3.2.3: {} - - convert-source-map@2.0.0: {} - - cross-spawn@7.0.3: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - csstype@3.1.3: {} - - dayjs@1.11.11: {} - - de-indent@1.0.2: {} - - debug@4.3.5: - dependencies: - ms: 2.1.2 - - defu@6.1.4: {} - - deprecation@2.3.1: {} - - destr@2.0.3: {} - - dotenv@16.4.5: {} - - electron-to-chromium@1.4.792: {} - - element-plus@2.7.4(vue@3.4.27(typescript@5.4.5)): - dependencies: - '@ctrl/tinycolor': 3.6.1 - '@element-plus/icons-vue': 2.3.1(vue@3.4.27(typescript@5.4.5)) - '@floating-ui/dom': 1.6.5 - '@popperjs/core': '@sxzz/popperjs-es@2.11.7' - '@types/lodash': 4.17.4 - '@types/lodash-es': 4.17.12 - '@vueuse/core': 9.13.0(vue@3.4.27(typescript@5.4.5)) - async-validator: 4.2.5 - dayjs: 1.11.11 - escape-html: 1.0.3 - lodash: 4.17.21 - lodash-es: 4.17.21 - lodash-unified: 1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21) - memoize-one: 6.0.0 - normalize-wheel-es: 1.2.0 - vue: 3.4.27(typescript@5.4.5) - transitivePeerDependencies: - - '@vue/composition-api' - - entities@4.5.0: {} - - esbuild@0.18.20: - optionalDependencies: - '@esbuild/android-arm': 0.18.20 - '@esbuild/android-arm64': 0.18.20 - '@esbuild/android-x64': 0.18.20 - '@esbuild/darwin-arm64': 0.18.20 - '@esbuild/darwin-x64': 0.18.20 - '@esbuild/freebsd-arm64': 0.18.20 - '@esbuild/freebsd-x64': 0.18.20 - '@esbuild/linux-arm': 0.18.20 - '@esbuild/linux-arm64': 0.18.20 - '@esbuild/linux-ia32': 0.18.20 - '@esbuild/linux-loong64': 0.18.20 - '@esbuild/linux-mips64el': 0.18.20 - '@esbuild/linux-ppc64': 0.18.20 - '@esbuild/linux-riscv64': 0.18.20 - '@esbuild/linux-s390x': 0.18.20 - '@esbuild/linux-x64': 0.18.20 - '@esbuild/netbsd-x64': 0.18.20 - '@esbuild/openbsd-x64': 0.18.20 - '@esbuild/sunos-x64': 0.18.20 - '@esbuild/win32-arm64': 0.18.20 - '@esbuild/win32-ia32': 0.18.20 - '@esbuild/win32-x64': 0.18.20 - - escalade@3.1.2: {} - - escape-html@1.0.3: {} - - escape-string-regexp@1.0.5: {} - - escape-string-regexp@5.0.0: {} - - estree-walker@2.0.2: {} - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.5 - - execa@8.0.1: - dependencies: - cross-spawn: 7.0.3 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 - - fast-glob@3.3.2: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.7 - - fastq@1.17.1: - dependencies: - reusify: 1.0.4 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - fs-extra@10.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - - fs-minipass@2.1.0: - dependencies: - minipass: 3.3.6 - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - gensync@1.0.0-beta.2: {} - - get-stream@8.0.1: {} - - giget@1.2.3: - dependencies: - citty: 0.1.6 - consola: 3.2.3 - defu: 6.1.4 - node-fetch-native: 1.6.4 - nypm: 0.3.8 - ohash: 1.1.3 - pathe: 1.1.2 - tar: 6.2.1 - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - globals@11.12.0: {} - - globby@14.0.1: - dependencies: - '@sindresorhus/merge-streams': 2.3.0 - fast-glob: 3.3.2 - ignore: 5.3.1 - path-type: 5.0.0 - slash: 5.1.0 - unicorn-magic: 0.1.0 - - globby@14.0.2: - dependencies: - '@sindresorhus/merge-streams': 2.3.0 - fast-glob: 3.3.2 - ignore: 5.3.2 - path-type: 5.0.0 - slash: 5.1.0 - unicorn-magic: 0.1.0 - optional: true - - graceful-fs@4.2.11: {} - - has-flag@3.0.0: {} - - hash-sum@2.0.0: {} - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - he@1.2.0: {} - - hookable@5.5.3: {} - - human-signals@5.0.0: {} - - ignore@5.3.1: {} - - ignore@5.3.2: - optional: true - - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - - is-core-module@2.13.1: - dependencies: - hasown: 2.0.2 - - is-extglob@2.1.1: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-number@7.0.0: {} - - is-plain-object@5.0.0: {} - - is-stream@3.0.0: {} - - isexe@2.0.0: {} - - jiti@1.21.3: {} - - jiti@1.21.6: - optional: true - - js-tokens@4.0.0: {} - - js-tokens@9.0.0: {} - - jsesc@2.5.2: {} - - json5@2.2.3: {} - - jsonfile@6.1.0: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - - klona@2.0.6: - optional: true - - knitwork@1.1.0: {} - - local-pkg@0.4.3: {} - - local-pkg@0.5.0: - dependencies: - mlly: 1.7.1 - pkg-types: 1.1.1 - - lodash-es@4.17.21: {} - - lodash-unified@1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21): - dependencies: - '@types/lodash-es': 4.17.12 - lodash: 4.17.21 - lodash-es: 4.17.21 - - lodash@4.17.21: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - magic-string@0.27.0: - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - - magic-string@0.29.0: - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - - magic-string@0.30.10: - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - - magic-string@0.30.11: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 - optional: true - - memoize-one@6.0.0: {} - - merge-stream@2.0.0: {} - - merge2@1.4.1: {} - - micromatch@4.0.7: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - - mimic-fn@4.0.0: {} - - minimatch@7.4.6: - dependencies: - brace-expansion: 2.0.1 - - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.1 - - minipass@3.3.6: - dependencies: - yallist: 4.0.0 - - minipass@5.0.0: {} - - minizlib@2.1.2: - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 - - mkdirp@1.0.4: {} - - mlly@1.7.1: - dependencies: - acorn: 8.11.3 - pathe: 1.1.2 - pkg-types: 1.1.1 - ufo: 1.5.3 - - mri@1.2.0: {} - - ms@2.1.2: {} - - muggle-string@0.4.1: {} - - nanoid@3.3.7: {} - - node-fetch-native@1.6.4: {} - - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - - node-releases@2.0.14: {} - - normalize-path@3.0.0: {} - - normalize-wheel-es@1.2.0: {} - - npm-run-path@5.3.0: - dependencies: - path-key: 4.0.0 - - nypm@0.3.8: - dependencies: - citty: 0.1.6 - consola: 3.2.3 - execa: 8.0.1 - pathe: 1.1.2 - ufo: 1.5.3 - - ohash@1.1.3: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onetime@6.0.0: - dependencies: - mimic-fn: 4.0.0 - - path-browserify@1.0.1: {} - - path-key@3.1.1: {} - - path-key@4.0.0: {} - - path-parse@1.0.7: {} - - path-type@5.0.0: {} - - pathe@1.1.2: {} - - perfect-debounce@1.0.0: {} - - picocolors@1.0.1: {} - - picomatch@2.3.1: {} - - pinia@2.1.7(typescript@5.4.5)(vue@3.4.27(typescript@5.4.5)): - dependencies: - '@vue/devtools-api': 6.6.3 - vue: 3.4.27(typescript@5.4.5) - vue-demi: 0.14.8(vue@3.4.27(typescript@5.4.5)) - optionalDependencies: - typescript: 5.4.5 - - pkg-types@1.1.1: - dependencies: - confbox: 0.1.7 - mlly: 1.7.1 - pathe: 1.1.2 - - pkg-types@1.1.3: - dependencies: - confbox: 0.1.7 - mlly: 1.7.1 - pathe: 1.1.2 - optional: true - - postcss@8.4.38: - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.1 - source-map-js: 1.2.0 - - queue-microtask@1.2.3: {} - - rc9@2.1.2: - dependencies: - defu: 6.1.4 - destr: 2.0.3 - - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 - - resolve@1.22.8: - dependencies: - is-core-module: 2.13.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - reusify@1.0.4: {} - - rollup@3.29.4: - optionalDependencies: - fsevents: 2.3.3 - - rollup@4.21.0: - dependencies: - '@types/estree': 1.0.5 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.21.0 - '@rollup/rollup-android-arm64': 4.21.0 - '@rollup/rollup-darwin-arm64': 4.21.0 - '@rollup/rollup-darwin-x64': 4.21.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.21.0 - '@rollup/rollup-linux-arm-musleabihf': 4.21.0 - '@rollup/rollup-linux-arm64-gnu': 4.21.0 - '@rollup/rollup-linux-arm64-musl': 4.21.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.21.0 - '@rollup/rollup-linux-riscv64-gnu': 4.21.0 - '@rollup/rollup-linux-s390x-gnu': 4.21.0 - '@rollup/rollup-linux-x64-gnu': 4.21.0 - '@rollup/rollup-linux-x64-musl': 4.21.0 - '@rollup/rollup-win32-arm64-msvc': 4.21.0 - '@rollup/rollup-win32-ia32-msvc': 4.21.0 - '@rollup/rollup-win32-x64-msvc': 4.21.0 - fsevents: 2.3.3 - optional: true - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - scule@1.3.0: {} - - semver@6.3.1: {} - - semver@7.6.2: {} - - semver@7.6.3: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - signal-exit@4.1.0: {} - - slash@5.1.0: {} - - sortablejs@1.14.0: {} - - source-map-js@1.2.0: {} - - std-env@3.7.0: {} - - strip-final-newline@3.0.0: {} - - strip-literal@1.3.0: - dependencies: - acorn: 8.11.3 - - strip-literal@2.1.0: - dependencies: - js-tokens: 9.0.0 - - supports-color@5.5.0: - dependencies: - has-flag: 3.0.0 - - supports-preserve-symlinks-flag@1.0.0: {} - - tar@6.2.1: - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - - to-fast-properties@2.0.0: {} - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - tr46@0.0.3: {} - - tunnel@0.0.6: {} - - typescript@5.4.5: {} - - ufo@1.5.3: {} - - ufo@1.5.4: - optional: true - - uncrypto@0.1.3: - optional: true - - unctx@2.3.1: - dependencies: - acorn: 8.11.3 - estree-walker: 3.0.3 - magic-string: 0.30.10 - unplugin: 1.10.1 - - undici-types@5.26.5: {} - - undici@5.28.4: - dependencies: - '@fastify/busboy': 2.1.1 - - unicorn-magic@0.1.0: {} - - unimport@2.2.4(rollup@4.21.0): - dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.21.0) - escape-string-regexp: 5.0.0 - fast-glob: 3.3.2 - local-pkg: 0.4.3 - magic-string: 0.27.0 - mlly: 1.7.1 - pathe: 1.1.2 - pkg-types: 1.1.1 - scule: 1.3.0 - strip-literal: 1.3.0 - unplugin: 1.10.1 - transitivePeerDependencies: - - rollup - - unimport@3.10.0(rollup@4.21.0): - dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.21.0) - acorn: 8.12.1 - escape-string-regexp: 5.0.0 - estree-walker: 3.0.3 - fast-glob: 3.3.2 - local-pkg: 0.5.0 - magic-string: 0.30.11 - mlly: 1.7.1 - pathe: 1.1.2 - pkg-types: 1.1.3 - scule: 1.3.0 - strip-literal: 2.1.0 - unplugin: 1.12.2 - transitivePeerDependencies: - - rollup - optional: true - - unimport@3.7.2(rollup@4.21.0): - dependencies: - '@rollup/pluginutils': 5.1.0(rollup@4.21.0) - acorn: 8.11.3 - escape-string-regexp: 5.0.0 - estree-walker: 3.0.3 - fast-glob: 3.3.2 - local-pkg: 0.5.0 - magic-string: 0.30.10 - mlly: 1.7.1 - pathe: 1.1.2 - pkg-types: 1.1.1 - scule: 1.3.0 - strip-literal: 2.1.0 - unplugin: 1.10.1 - transitivePeerDependencies: - - rollup - - universal-user-agent@6.0.1: {} - - universalify@2.0.1: {} - - unplugin-auto-import@0.14.4(@vueuse/core@10.10.0(vue@3.4.27(typescript@5.4.5)))(rollup@4.21.0): - dependencies: - '@antfu/utils': 0.7.8 - '@nuxt/kit': 3.11.2(rollup@4.21.0) - '@rollup/pluginutils': 5.1.0(rollup@4.21.0) - local-pkg: 0.4.3 - magic-string: 0.29.0 - minimatch: 7.4.6 - unimport: 2.2.4(rollup@4.21.0) - unplugin: 1.10.1 - optionalDependencies: - '@vueuse/core': 10.10.0(vue@3.4.27(typescript@5.4.5)) - transitivePeerDependencies: - - rollup - - supports-color - - unplugin-vue-components@0.24.1(@babel/parser@7.25.3)(@nuxt/kit@3.12.4(rollup@4.21.0))(rollup@4.21.0)(vue@3.4.27(typescript@5.4.5)): - dependencies: - '@antfu/utils': 0.7.8 - '@rollup/pluginutils': 5.1.0(rollup@4.21.0) - chokidar: 3.6.0 - debug: 4.3.5 - fast-glob: 3.3.2 - local-pkg: 0.4.3 - magic-string: 0.30.10 - minimatch: 7.4.6 - resolve: 1.22.8 - unplugin: 1.10.1 - vue: 3.4.27(typescript@5.4.5) - optionalDependencies: - '@babel/parser': 7.25.3 - '@nuxt/kit': 3.12.4(rollup@4.21.0) - transitivePeerDependencies: - - rollup - - supports-color - - unplugin@1.10.1: - dependencies: - acorn: 8.11.3 - chokidar: 3.6.0 - webpack-sources: 3.2.3 - webpack-virtual-modules: 0.6.2 - - unplugin@1.12.2: - dependencies: - acorn: 8.12.1 - chokidar: 3.6.0 - webpack-sources: 3.2.3 - webpack-virtual-modules: 0.6.2 - optional: true - - untyped@1.4.2: - dependencies: - '@babel/core': 7.24.7 - '@babel/standalone': 7.24.7 - '@babel/types': 7.24.7 - defu: 6.1.4 - jiti: 1.21.3 - mri: 1.2.0 - scule: 1.3.0 - transitivePeerDependencies: - - supports-color - - update-browserslist-db@1.0.16(browserslist@4.23.0): - dependencies: - browserslist: 4.23.0 - escalade: 3.1.2 - picocolors: 1.0.1 - - uuid@9.0.1: {} - - vite@4.5.3(@types/node@18.19.34): - dependencies: - esbuild: 0.18.20 - postcss: 8.4.38 - rollup: 3.29.4 - optionalDependencies: - '@types/node': 18.19.34 - fsevents: 2.3.3 - - vscode-uri@3.0.8: {} - - vue-demi@0.14.8(vue@3.4.27(typescript@5.4.5)): - dependencies: - vue: 3.4.27(typescript@5.4.5) - - vue-i18n@9.13.1(vue@3.4.27(typescript@5.4.5)): - dependencies: - '@intlify/core-base': 9.13.1 - '@intlify/shared': 9.13.1 - '@vue/devtools-api': 6.6.3 - vue: 3.4.27(typescript@5.4.5) - - vue-router@4.3.2(vue@3.4.27(typescript@5.4.5)): - dependencies: - '@vue/devtools-api': 6.6.3 - vue: 3.4.27(typescript@5.4.5) - - vue-tsc@2.0.29(typescript@5.4.5): - dependencies: - '@volar/typescript': 2.4.0 - '@vue/language-core': 2.0.29(typescript@5.4.5) - semver: 7.6.3 - typescript: 5.4.5 - - vue@3.4.27(typescript@5.4.5): - dependencies: - '@vue/compiler-dom': 3.4.27 - '@vue/compiler-sfc': 3.4.27 - '@vue/runtime-dom': 3.4.27 - '@vue/server-renderer': 3.4.27(vue@3.4.27(typescript@5.4.5)) - '@vue/shared': 3.4.27 - optionalDependencies: - typescript: 5.4.5 - - vuedraggable@4.1.0(vue@3.4.27(typescript@5.4.5)): - dependencies: - sortablejs: 1.14.0 - vue: 3.4.27(typescript@5.4.5) - - webidl-conversions@3.0.1: {} - - webpack-sources@3.2.3: {} - - webpack-virtual-modules@0.6.2: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - wrappy@1.0.2: {} - - yallist@3.1.1: {} - - yallist@4.0.0: {} + dev: true diff --git a/src-tauri/src/archive.rs b/src-tauri/src/backup/archive.rs similarity index 95% rename from src-tauri/src/archive.rs rename to src-tauri/src/backup/archive.rs index 03c1d36..afdea0a 100644 --- a/src-tauri/src/archive.rs +++ b/src-tauri/src/backup/archive.rs @@ -11,7 +11,7 @@ use tauri::{AppHandle, Manager}; use zip::{write::SimpleFileOptions, ZipWriter}; use crate::{ - config::{SaveUnit, SaveUnitType}, + backup::{SaveUnit, SaveUnitType}, errors::{BackupFileError, CompressError}, ipc_handler::{IpcNotification, NotificationLevel}, }; @@ -161,7 +161,9 @@ pub fn decompress_from_file( title: "WARNING".to_string(), msg: t!( "backend.archive.file_not_exist", - path = prefix_root.to_str().unwrap_or("prefix_root.to_str error") + path = prefix_root + .to_str() + .unwrap_or("prefix_root.to_str error") ) .to_string(), }, @@ -188,7 +190,9 @@ pub fn decompress_from_file( title: "WARNING".to_string(), msg: t!( "backend.archive.file_not_exist", - path = target_path.to_str().unwrap_or("target_path.to_str() error") + path = target_path + .to_str() + .unwrap_or("target_path.to_str() error") ) .to_string(), }, diff --git a/src-tauri/src/backup.rs b/src-tauri/src/backup/game.rs similarity index 62% rename from src-tauri/src/backup.rs rename to src-tauri/src/backup/game.rs index 72a9119..7e50af0 100644 --- a/src-tauri/src/backup.rs +++ b/src-tauri/src/backup/game.rs @@ -1,35 +1,29 @@ -use crate::archive::{compress_to_file, decompress_from_file}; -use crate::cloud::{upload_backup_info, upload_config}; -use crate::config::{get_config, set_config, Game}; +use serde::{Deserialize, Serialize}; + +use crate::cloud_sync::{upload_config, upload_game_snapshots}; +use crate::config::{get_config, set_config}; use crate::errors::BackupError; use crate::ipc_handler::{IpcNotification, NotificationLevel}; -use serde::{Deserialize, Serialize}; use std::path::PathBuf; use std::{fs, path}; use tauri::{AppHandle, Manager}; use tracing::{error, info}; -/// A backup is a zip file that contains -/// all the file that the save unit has declared. -/// The date is the unique indicator for a backup -#[derive(Debug, Serialize, Deserialize)] -pub struct Backup { - pub date: String, - pub describe: String, - pub path: String, // like "D:\\SaveManager\save_data\Game1\date.zip" -} +use super::GameSnapshots; +use super::SaveUnit; +use super::Snapshot; +use super::{compress_to_file, decompress_from_file}; -/// A backup list info is a json file in a backup folder for a game. -/// It contains the name of the game, -/// and all backups' path -#[derive(Debug, Serialize, Deserialize)] -pub struct BackupListInfo { +/// A game struct contains the save units and the game's launcher +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Game { pub name: String, - pub backups: Vec, + pub save_paths: Vec, + pub game_path: Option, } impl Game { - pub fn get_backup_list_info(&self) -> Result { + pub fn get_game_snapshots_info(&self) -> Result { let config = get_config()?; let backup_path = path::Path::new(&config.backup_path) .join(&self.name) @@ -37,7 +31,7 @@ impl Game { let backup_info = serde_json::from_slice(&fs::read(backup_path)?)?; Ok(backup_info) } - pub fn set_backup_list_info(&self, new_info: &BackupListInfo) -> Result<(), BackupError> { + pub fn set_game_snapshots_info(&self, new_info: &GameSnapshots) -> Result<(), BackupError> { let config = get_config()?; let saves_path = path::Path::new(&config.backup_path) .join(&self.name) @@ -50,7 +44,7 @@ impl Game { fs::write(saves_path, serde_json::to_string_pretty(&new_info)?)?; Ok(()) } - pub async fn backup_save(&self, describe: &str) -> Result<(), BackupError> { + pub async fn create_snapshot(&self, describe: &str) -> Result<(), BackupError> { let config = get_config()?; let backup_path = path::Path::new(&config.backup_path).join(&self.name); // the backup zip file should be placed here let date = chrono::Local::now().format("%Y-%m-%d_%H-%M-%S").to_string(); @@ -63,7 +57,7 @@ impl Game { return Err(BackupError::CompressError(e)); } - let backup_list_info = Backup { + let game_snapshots_info = Snapshot { date, describe: describe.to_string(), path: zip_path @@ -71,15 +65,15 @@ impl Game { .ok_or(BackupError::NonePathError)? .to_string(), }; - let mut infos = self.get_backup_list_info()?; - infos.backups.push(backup_list_info); - self.set_backup_list_info(&infos)?; + let mut infos = self.get_game_snapshots_info()?; + infos.backups.push(game_snapshots_info); + self.set_game_snapshots_info(&infos)?; // 随时同步到云端 if config.settings.cloud_settings.always_sync { let op = config.settings.cloud_settings.backend.get_op()?; // 上传存档记录信息 - upload_backup_info(&op, infos).await?; + upload_game_snapshots(&op, infos).await?; // 上传对应压缩包 // 此处防止路径中出现反斜杠,导致云端无法识别,替换win的反斜杠为斜杠 let p = zip_path @@ -91,13 +85,13 @@ impl Game { } Result::Ok(()) } - pub fn apply_backup(&self, date: &str, app_handle: &AppHandle) -> Result<(), BackupError> { + pub fn restore_snapshot(&self, date: &str, app_handle: &AppHandle) -> Result<(), BackupError> { let config = get_config()?; let backup_path = path::Path::new(&config.backup_path).join(&self.name); if config.settings.extra_backup_when_apply { - info!(target:"rgsm::backup","Creating extra backup."); - if let Err(e) = self.create_extra_backup() { - error!(target:"rgsm::backup","Failed to create extra backup: {:?}", e); + info!(target:"rgsm::backup::game","Creating extra backup."); + if let Err(e) = self.create_overwrite_snapshot() { + error!(target:"rgsm::backup::game","Failed to create extra backup: {:?}", e); app_handle .emit_all( "Notification", @@ -114,7 +108,7 @@ impl Game { decompress_from_file(&self.save_paths, &backup_path, date, app_handle)?; Result::Ok(()) } - pub fn create_extra_backup(&self) -> Result<(), BackupError> { + pub fn create_overwrite_snapshot(&self) -> Result<(), BackupError> { let config = get_config()?; let extra_backup_path = path::Path::new(&config.backup_path) .join(&self.name) @@ -150,22 +144,22 @@ impl Game { } Result::Ok(()) } - pub async fn delete_backup(&self, date: &str) -> Result<(), BackupError> { + pub async fn delete_snapshot(&self, date: &str) -> Result<(), BackupError> { let config = get_config()?; let save_path = PathBuf::from(&config.backup_path) .join(&self.name) .join(date.to_string() + ".zip"); fs::remove_file(&save_path)?; - let mut saves = self.get_backup_list_info()?; + let mut saves = self.get_game_snapshots_info()?; saves.backups.retain(|x| x.date != date); - self.set_backup_list_info(&saves)?; + self.set_game_snapshots_info(&saves)?; // 随时同步到云端 if config.settings.cloud_settings.always_sync { let op = config.settings.cloud_settings.backend.get_op()?; // 上传存档记录信息 - upload_backup_info(&op, saves).await?; + upload_game_snapshots(&op, saves).await?; // 删除对应压缩包 // 此处防止路径中出现反斜杠,导致云端无法识别,替换win的反斜杠为斜杠 let p = save_path @@ -188,7 +182,7 @@ impl Game { // 随时同步到云端 if config.settings.cloud_settings.always_sync { let op = config.settings.cloud_settings.backend.get_op()?; - info!(target:"rgsm::cloud", + info!(target:"rgsm::backup::game", "Delete Game: {:#?}", backup_path.to_str().ok_or(BackupError::NonePathError)? ); @@ -205,8 +199,12 @@ impl Game { Ok(()) } - pub async fn set_backup_describe(&self, date: &str, describe: &str) -> Result<(), BackupError> { - let mut saves = self.get_backup_list_info()?; + pub async fn set_snapshot_description( + &self, + date: &str, + describe: &str, + ) -> Result<(), BackupError> { + let mut saves = self.get_game_snapshots_info()?; let pos = saves.backups.iter().position(|x| x.date == date).ok_or( BackupError::BackupNotExist { name: self.name.clone(), @@ -214,79 +212,7 @@ impl Game { }, )?; saves.backups[pos].describe = describe.to_string(); - self.set_backup_list_info(&saves)?; + self.set_game_snapshots_info(&saves)?; Ok(()) } } - -async fn create_backup_folder(name: &str) -> Result<(), BackupError> { - let config = get_config()?; - - let backup_path = PathBuf::from(&config.backup_path).join(name); - let info: BackupListInfo = if !backup_path.exists() { - fs::create_dir_all(&backup_path)?; - BackupListInfo { - name: name.to_string(), - backups: Vec::new(), - } - } else { - // 如果已经存在,info从原来的文件中读取 - let bytes = fs::read(backup_path.join("Backups.json")); - serde_json::from_slice(&bytes?)? - }; - fs::write( - backup_path.join("Backups.json"), - serde_json::to_string_pretty(&info)?, - )?; - - // 处理云同步 - if config.settings.cloud_settings.always_sync { - let op = config.settings.cloud_settings.backend.get_op()?; - // 上传存档记录信息 - upload_backup_info(&op, info).await?; - } - - Ok(()) -} - -pub async fn create_game_backup(game: &Game) -> Result<(), BackupError> { - let mut config = get_config()?; - create_backup_folder(&game.name).await?; - - // 查找是否存在与新游戏中的 `name` 字段相同的游戏 - let pos = config.games.iter().position(|g| g.name == game.name); - match pos { - Some(index) => { - // 如果找到了,就用新的游戏覆盖它 - config.games[index] = game.clone(); - } - None => { - // 如果没有找到,就将新的游戏添加到 `games` 数组中 - config.games.push(game.clone()); - } - } - set_config(&config).await?; - Ok(()) -} - -pub async fn backup_all() -> Result<(), BackupError> { - let config = get_config()?; - for game in &config.games { - game.backup_save("Backup all").await?; - } - Ok(()) -} -pub async fn apply_all(app_handle: &AppHandle) -> Result<(), BackupError> { - let config = get_config()?; - for game in &config.games { - let date = game - .get_backup_list_info()? - .backups - .last() - .ok_or(BackupError::NoBackupAvailable)? - .date - .clone(); - game.apply_backup(&date, app_handle)?; - } - Ok(()) -} diff --git a/src-tauri/src/backup/game_snapshots.rs b/src-tauri/src/backup/game_snapshots.rs new file mode 100644 index 0000000..2ed8432 --- /dev/null +++ b/src-tauri/src/backup/game_snapshots.rs @@ -0,0 +1,14 @@ +use serde::{Deserialize, Serialize}; + +use super::Snapshot; + + + +/// A backup list info is a json file in a backup folder for a game. +/// It contains the name of the game, +/// and all backups' path +#[derive(Debug, Serialize, Deserialize)] +pub struct GameSnapshots { + pub name: String, + pub backups: Vec, +} \ No newline at end of file diff --git a/src-tauri/src/backup/mod.rs b/src-tauri/src/backup/mod.rs new file mode 100644 index 0000000..163aaca --- /dev/null +++ b/src-tauri/src/backup/mod.rs @@ -0,0 +1,13 @@ +mod archive; +mod game; +mod game_snapshots; +mod save_unit; +mod snapshot; +mod utils; + +use archive::{compress_to_file, decompress_from_file}; +pub use game::Game; +pub use game_snapshots::GameSnapshots; +pub use save_unit::{SaveUnit, SaveUnitType}; +pub use snapshot::Snapshot; +pub use utils::*; diff --git a/src-tauri/src/backup/save_unit.rs b/src-tauri/src/backup/save_unit.rs new file mode 100644 index 0000000..6e75a93 --- /dev/null +++ b/src-tauri/src/backup/save_unit.rs @@ -0,0 +1,20 @@ +use serde::{Deserialize, Serialize}; + +use crate::default_value; + +/// A save unit should be a file or a folder +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum SaveUnitType { + File, + Folder, +} + +/// A save unit declares one of the files/folders +/// that should be backup for a game +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct SaveUnit { + pub unit_type: SaveUnitType, + pub path: String, + #[serde(default = "default_value::default_false")] + pub delete_before_apply: bool, +} diff --git a/src-tauri/src/backup/snapshot.rs b/src-tauri/src/backup/snapshot.rs new file mode 100644 index 0000000..5f05c93 --- /dev/null +++ b/src-tauri/src/backup/snapshot.rs @@ -0,0 +1,11 @@ +use serde::{Deserialize, Serialize}; + +/// A backup is a zip file that contains +/// all the file that the save unit has declared. +/// The date is the unique indicator for a backup +#[derive(Debug, Serialize, Deserialize)] +pub struct Snapshot { + pub date: String, + pub describe: String, + pub path: String, // like "D:\\SaveManager\save_data\Game1\date.zip" +} \ No newline at end of file diff --git a/src-tauri/src/backup/utils.rs b/src-tauri/src/backup/utils.rs new file mode 100644 index 0000000..6b990c7 --- /dev/null +++ b/src-tauri/src/backup/utils.rs @@ -0,0 +1,80 @@ +use crate::cloud_sync::upload_game_snapshots; +use crate::config::{get_config, set_config}; +use crate::errors::BackupError; +use std::fs; +use std::path::PathBuf; +use tauri::AppHandle; + +use super::{Game, GameSnapshots}; + +async fn create_backup_folder(name: &str) -> Result<(), BackupError> { + let config = get_config()?; + + let backup_path = PathBuf::from(&config.backup_path).join(name); + let info: GameSnapshots = if !backup_path.exists() { + fs::create_dir_all(&backup_path)?; + GameSnapshots { + name: name.to_string(), + backups: Vec::new(), + } + } else { + // 如果已经存在,info从原来的文件中读取 + let bytes = fs::read(backup_path.join("Backups.json")); + serde_json::from_slice(&bytes?)? + }; + fs::write( + backup_path.join("Backups.json"), + serde_json::to_string_pretty(&info)?, + )?; + + // 处理云同步 + if config.settings.cloud_settings.always_sync { + let op = config.settings.cloud_settings.backend.get_op()?; + // 上传存档记录信息 + upload_game_snapshots(&op, info).await?; + } + + Ok(()) +} + +pub async fn create_game_backup(game: &Game) -> Result<(), BackupError> { + let mut config = get_config()?; + create_backup_folder(&game.name).await?; + + // 查找是否存在与新游戏中的 `name` 字段相同的游戏 + let pos = config.games.iter().position(|g| g.name == game.name); + match pos { + Some(index) => { + // 如果找到了,就用新的游戏覆盖它 + config.games[index] = game.clone(); + } + None => { + // 如果没有找到,就将新的游戏添加到 `games` 数组中 + config.games.push(game.clone()); + } + } + set_config(&config).await?; + Ok(()) +} + +pub async fn backup_all() -> Result<(), BackupError> { + let config = get_config()?; + for game in &config.games { + game.create_snapshot("Backup all").await?; + } + Ok(()) +} +pub async fn apply_all(app_handle: &AppHandle) -> Result<(), BackupError> { + let config = get_config()?; + for game in &config.games { + let date = game + .get_game_snapshots_info()? + .backups + .last() + .ok_or(BackupError::NoBackupAvailable)? + .date + .clone(); + game.restore_snapshot(&date, app_handle)?; + } + Ok(()) +} diff --git a/src-tauri/src/cloud.rs b/src-tauri/src/cloud.rs deleted file mode 100644 index 6541a8b..0000000 --- a/src-tauri/src/cloud.rs +++ /dev/null @@ -1,219 +0,0 @@ -use std::fs; - -use opendal::services; -use opendal::Operator; -use serde::{Deserialize, Serialize}; -use tracing::info; - -use crate::backup::BackupListInfo; -use crate::config::{get_config, set_config, Config}; -use crate::default_value; -use crate::errors::BackendError; -use crate::traits::Sanitizable; - -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(tag = "type")] -pub enum Backend { - // TODO:增加更多后端支持 - Disabled, - /// WebDAV 后端 - /// 参考:https://docs.rs/opendal/latest/opendal/services/struct.Webdav.html - /// 不支持 blocking - WebDAV { - endpoint: String, - username: String, - password: String, - }, - /// Amazon S3 后端 - /// 参考:https://docs.rs/opendal/latest/opendal/services/struct.S3.html - /// 不支持 rename 和 blocking - S3 { - endpoint: String, - bucket: String, - region: String, - access_key_id: String, - secret_access_key: String, - }, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct CloudSettings { - /// 是否启用跟随云同步(用户添加、删除时自动同步) - #[serde(default = "default_value::default_false")] - pub always_sync: bool, - /// 同步间隔,单位分钟,为0则不自动同步 - #[serde(default = "default_value::default_zero")] - pub auto_sync_interval: u64, - /// 云同步根目录 - #[serde(default = "default_value::default_root_path")] - pub root_path: String, - /// 云同步后端设置 - #[serde(default = "default_value::default_backend")] - pub backend: Backend, -} - -impl Sanitizable for CloudSettings { - fn sanitize(self) -> Self { - CloudSettings { - backend: self.backend.sanitize(), - ..self - } - } -} - -impl Backend { - /// 获取 Operator 实例 - pub fn get_op(&self) -> Result { - let root = get_config()?.settings.cloud_settings.root_path; - match self { - Backend::Disabled => Err(BackendError::Disabled), - Backend::WebDAV { - endpoint, - username, - password, - } => { - let mut builder = services::Webdav::default(); - builder.endpoint(endpoint); - builder.username(username); - builder.password(password); - builder.root(&root); - Ok(Operator::new(builder)?.finish()) - } - Backend::S3 { - endpoint, - bucket, - region, - access_key_id, - secret_access_key, - } => { - let mut builder = services::S3::default(); - builder.endpoint(endpoint); - builder.bucket(bucket); - builder.region(region); - builder.access_key_id(access_key_id); - builder.secret_access_key(secret_access_key); - builder.root(&root); - Ok(Operator::new(builder)?.finish()) - } - } - } - - /// 检查后端是否可用 - pub async fn check(&self) -> Result<(), BackendError> { - self.get_op()?.check().await?; - Ok(()) - } -} - -impl Sanitizable for Backend { - fn sanitize(self) -> Self { - match self { - Backend::Disabled => Backend::Disabled, - Backend::WebDAV { - endpoint, - username: _, - password: _, - } => Backend::WebDAV { - endpoint: endpoint.clone(), - username: "*username*".to_string(), - password: "*password*".to_string(), - }, - Backend::S3 { - endpoint: _, - bucket: _, - region: _, - access_key_id: _, - secret_access_key: _, - } => Backend::S3 { - endpoint: "*endpoint*".to_string(), - bucket: "*bucket*".to_string(), - region: "*region*".to_string(), - access_key_id: "*access_key_id*".to_string(), - secret_access_key: "*secret_access_key*".to_string(), - }, - } - } -} - -pub async fn upload_all(op: &Operator) -> Result<(), BackendError> { - let config = get_config()?; - // 上传配置文件 - upload_config(op).await?; - // 依次上传所有游戏的存档记录和存档 - for game in config.games { - // !NOTICE: 这个地方必须硬编码,因为云端目录必须固定 - let cloud_backup_path = format!("save_data/{}", game.name); - let backup_info = game.get_backup_list_info()?; - // 写入存档记录 - op.write( - &format!("{}/Backups.json", &cloud_backup_path), - serde_json::to_string_pretty(&backup_info)?, - ) - .await?; - // 写入存档zip文件(不包括额外备份) - for backup in backup_info.backups { - // TODO: 此处的cloud_backup_path应当改为本地的路径 - let save_path = format!("{}/{}.zip", &cloud_backup_path, backup.date); - info!(target:"rgsm::cloud","Uploading {}", save_path); - op.write(&save_path, fs::read(&save_path)?).await?; - } - } - Ok(()) -} - -pub async fn download_all(op: &Operator) -> Result<(), BackendError> { - // 下载配置文件 - let config = String::from_utf8(op.read("/GameSaveManager.config.json").await?.to_vec())?; - let config: Config = serde_json::from_str(&config)?; - set_config(&config).await?; - // 依次下载所有游戏的存档记录和存档 - for game in config.games { - // !NOTICE: 这个地方必须硬编码,因为云端目录必须固定 - let backup_path = format!("save_data/{}", game.name); - let backup_info = op - .read(&format!("{}/Backups.json", &backup_path)) - .await? - .to_vec(); - let backup_info: BackupListInfo = serde_json::from_str(&String::from_utf8(backup_info)?)?; - game.set_backup_list_info(&backup_info)?; - // 写入存档记录 - // TODO: 此处的cloud_backup_path应当改为本地的路径 - fs::write( - &format!("{}/Backups.json", &backup_path), - serde_json::to_string_pretty(&backup_info)?, - )?; - // 写入存档zip文件(不包括额外备份) - for backup in backup_info.backups { - let save_path = format!("{}/{}.zip", &backup_path, backup.date); - info!(target:"rgsm::cloud","Downloading {}", save_path); - let data = op.read(&save_path).await?.to_vec(); - fs::write(&save_path, &data)?; - } - } - Ok(()) -} - -/// 上传单个游戏的配置文件 -pub async fn upload_backup_info(op: &Operator, info: BackupListInfo) -> Result<(), BackendError> { - // !NOTICE: 这个地方必须硬编码,因为云端目录必须固定 - let backup_path = format!("save_data/{}", info.name); - op.write( - &format!("{}/Backups.json", &backup_path), - serde_json::to_string_pretty(&info)?, - ) - .await?; - Ok(()) -} - -// 上传配置文件 -pub async fn upload_config(op: &Operator) -> Result<(), BackendError> { - // !NOTICE: 这个地方必须硬编码,因为云端目录必须固定 - let config = get_config()?; - // 上传配置文件 - op.write( - "/GameSaveManager.config.json", - serde_json::to_string_pretty(&config)?, - ) - .await?; - Ok(()) -} diff --git a/src-tauri/src/cloud_sync/backend.rs b/src-tauri/src/cloud_sync/backend.rs new file mode 100644 index 0000000..68a1eec --- /dev/null +++ b/src-tauri/src/cloud_sync/backend.rs @@ -0,0 +1,106 @@ +use opendal::services; +use opendal::Operator; +use serde::{Deserialize, Serialize}; + +use crate::config::get_config; +use crate::errors::BackendError; +use crate::traits::Sanitizable; + +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(tag = "type")] +pub enum Backend { + // TODO:增加更多后端支持 + Disabled, + /// WebDAV 后端 + /// 参考:https://docs.rs/opendal/latest/opendal/services/struct.Webdav.html + /// 不支持 blocking + WebDAV { + endpoint: String, + username: String, + password: String, + }, + /// Amazon S3 后端 + /// 参考:https://docs.rs/opendal/latest/opendal/services/struct.S3.html + /// 不支持 rename 和 blocking + S3 { + endpoint: String, + bucket: String, + region: String, + access_key_id: String, + secret_access_key: String, + }, +} + +impl Backend { + /// 获取 Operator 实例 + pub fn get_op(&self) -> Result { + let root = get_config()?.settings.cloud_settings.root_path; + match self { + Backend::Disabled => Err(BackendError::Disabled), + Backend::WebDAV { + endpoint, + username, + password, + } => { + let mut builder = services::Webdav::default(); + builder.endpoint(endpoint); + builder.username(username); + builder.password(password); + builder.root(&root); + Ok(Operator::new(builder)?.finish()) + } + Backend::S3 { + endpoint, + bucket, + region, + access_key_id, + secret_access_key, + } => { + let mut builder = services::S3::default(); + builder.endpoint(endpoint); + builder.bucket(bucket); + builder.region(region); + builder.access_key_id(access_key_id); + builder.secret_access_key(secret_access_key); + builder.root(&root); + Ok(Operator::new(builder)?.finish()) + } + } + } + + /// 检查后端是否可用 + pub async fn check(&self) -> Result<(), BackendError> { + self.get_op()?.check().await?; + Ok(()) + } +} + +impl Sanitizable for Backend { + fn sanitize(self) -> Self { + match self { + Backend::Disabled => Backend::Disabled, + Backend::WebDAV { + endpoint, + username: _, + password: _, + } => Backend::WebDAV { + endpoint: endpoint.clone(), + username: "*username*".to_string(), + password: "*password*".to_string(), + }, + Backend::S3 { + endpoint: _, + bucket: _, + region: _, + access_key_id: _, + secret_access_key: _, + } => Backend::S3 { + endpoint: "*endpoint*".to_string(), + bucket: "*bucket*".to_string(), + region: "*region*".to_string(), + access_key_id: "*access_key_id*".to_string(), + secret_access_key: "*secret_access_key*".to_string(), + }, + } + } +} diff --git a/src-tauri/src/cloud_sync/cloud_settings.rs b/src-tauri/src/cloud_sync/cloud_settings.rs new file mode 100644 index 0000000..b2eecf1 --- /dev/null +++ b/src-tauri/src/cloud_sync/cloud_settings.rs @@ -0,0 +1,31 @@ +use serde::{Deserialize, Serialize}; + +use crate::default_value; +use crate::traits::Sanitizable; + +use super::Backend; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CloudSettings { + /// 是否启用跟随云同步(用户添加、删除时自动同步) + #[serde(default = "default_value::default_false")] + pub always_sync: bool, + /// 同步间隔,单位分钟,为0则不自动同步 + #[serde(default = "default_value::default_zero")] + pub auto_sync_interval: u64, + /// 云同步根目录 + #[serde(default = "default_value::default_root_path")] + pub root_path: String, + /// 云同步后端设置 + #[serde(default = "default_value::default_backend")] + pub backend: Backend, +} + +impl Sanitizable for CloudSettings { + fn sanitize(self) -> Self { + CloudSettings { + backend: self.backend.sanitize(), + ..self + } + } +} diff --git a/src-tauri/src/cloud_sync/mod.rs b/src-tauri/src/cloud_sync/mod.rs new file mode 100644 index 0000000..b0da273 --- /dev/null +++ b/src-tauri/src/cloud_sync/mod.rs @@ -0,0 +1,7 @@ +mod backend; +mod cloud_settings; +mod utils; + +pub use backend::Backend; +pub use cloud_settings::CloudSettings; +pub use utils::*; \ No newline at end of file diff --git a/src-tauri/src/cloud_sync/utils.rs b/src-tauri/src/cloud_sync/utils.rs new file mode 100644 index 0000000..5c78f4e --- /dev/null +++ b/src-tauri/src/cloud_sync/utils.rs @@ -0,0 +1,91 @@ +use std::fs; + +use opendal::Operator; +use tracing::info; + +use crate::backup::GameSnapshots; +use crate::config::{get_config, set_config, Config}; +use crate::errors::BackendError; + +pub async fn upload_all(op: &Operator) -> Result<(), BackendError> { + let config = get_config()?; + // 上传配置文件 + upload_config(op).await?; + // 依次上传所有游戏的存档记录和存档 + for game in config.games { + // !NOTICE: 这个地方必须硬编码,因为云端目录必须固定 + let cloud_backup_path = format!("save_data/{}", game.name); + let backup_info = game.get_game_snapshots_info()?; + // 写入存档记录 + op.write( + &format!("{}/Backups.json", &cloud_backup_path), + serde_json::to_string_pretty(&backup_info)?, + ) + .await?; + // 写入存档zip文件(不包括额外备份) + for backup in backup_info.backups { + // TODO: 此处的cloud_backup_path应当改为本地的路径 + let save_path = format!("{}/{}.zip", &cloud_backup_path, backup.date); + info!(target:"rgsm::cloud::utils","Uploading {}", save_path); + op.write(&save_path, fs::read(&save_path)?).await?; + } + } + Ok(()) +} + +pub async fn download_all(op: &Operator) -> Result<(), BackendError> { + // 下载配置文件 + let config = String::from_utf8(op.read("/GameSaveManager.config.json").await?.to_vec())?; + let config: Config = serde_json::from_str(&config)?; + set_config(&config).await?; + // 依次下载所有游戏的存档记录和存档 + for game in config.games { + // !NOTICE: 这个地方必须硬编码,因为云端目录必须固定 + let backup_path = format!("save_data/{}", game.name); + let backup_info = op + .read(&format!("{}/Backups.json", &backup_path)) + .await? + .to_vec(); + let backup_info: GameSnapshots = serde_json::from_str(&String::from_utf8(backup_info)?)?; + game.set_game_snapshots_info(&backup_info)?; + // 写入存档记录 + // TODO: 此处的cloud_backup_path应当改为本地的路径 + fs::write( + &format!("{}/Backups.json", &backup_path), + serde_json::to_string_pretty(&backup_info)?, + )?; + // 写入存档zip文件(不包括额外备份) + for backup in backup_info.backups { + let save_path = format!("{}/{}.zip", &backup_path, backup.date); + info!(target:"rgsm::cloud::utils","Downloading {}", save_path); + let data = op.read(&save_path).await?.to_vec(); + fs::write(&save_path, &data)?; + } + } + Ok(()) +} + +/// 上传单个游戏的配置文件 +pub async fn upload_game_snapshots(op: &Operator, info: GameSnapshots) -> Result<(), BackendError> { + // !NOTICE: 这个地方必须硬编码,因为云端目录必须固定 + let backup_path = format!("save_data/{}", info.name); + op.write( + &format!("{}/Backups.json", &backup_path), + serde_json::to_string_pretty(&info)?, + ) + .await?; + Ok(()) +} + +// 上传配置文件 +pub async fn upload_config(op: &Operator) -> Result<(), BackendError> { + // !NOTICE: 这个地方必须硬编码,因为云端目录必须固定 + let config = get_config()?; + // 上传配置文件 + op.write( + "/GameSaveManager.config.json", + serde_json::to_string_pretty(&config)?, + ) + .await?; + Ok(()) +} diff --git a/src-tauri/src/config.rs b/src-tauri/src/config.rs deleted file mode 100644 index 5363b51..0000000 --- a/src-tauri/src/config.rs +++ /dev/null @@ -1,239 +0,0 @@ -use std::fs::File; -use std::{fs, path}; - -use rust_i18n::t; -use semver::Version; -use serde::{Deserialize, Serialize}; -use tauri::api::notification::Notification; -use tracing::info; - -use crate::cloud::CloudSettings; -use crate::default_value; -use crate::errors::ConfigError; -use crate::traits::Sanitizable; - -/// A save unit should be a file or a folder -#[derive(Debug, Serialize, Deserialize, Clone)] -pub enum SaveUnitType { - File, - Folder, -} - -/// A save unit declares one of the files/folders -/// that should be backup for a game -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct SaveUnit { - pub unit_type: SaveUnitType, - pub path: String, - #[serde(default = "default_value::default_false")] - pub delete_before_apply: bool, -} - -/// A game struct contains the save units and the game's launcher -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct Game { - pub name: String, - pub save_paths: Vec, - pub game_path: Option, -} - -/// Settings that can be configured by user -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct Settings { - #[serde(default = "default_value::default_true")] - pub prompt_when_not_described: bool, - #[serde(default = "default_value::default_true")] - pub extra_backup_when_apply: bool, - #[serde(default = "default_value::default_false")] - pub show_edit_button: bool, - #[serde(default = "default_value::default_true")] - pub prompt_when_auto_backup: bool, - #[serde(default = "default_value::default_true")] - pub exit_to_tray: bool, - #[serde(default = "default_value::default_cloud_settings")] - pub cloud_settings: CloudSettings, - #[serde(default = "default_value::default_locale")] - pub locale: String, - #[serde(default = "default_value::default_false")] - pub default_delete_before_apply: bool, - #[serde(default = "default_value::default_false")] - pub default_expend_favorites_tree: bool, - #[serde(default = "default_value::default_home_page")] - pub home_page: String, - #[serde(default = "default_value::default_true")] - pub log_to_file: bool, - #[serde(default = "default_value::default_false")] - pub add_new_to_favorites: bool, -} - -impl Sanitizable for Settings { - fn sanitize(self) -> Self { - Settings { - cloud_settings: self.cloud_settings.sanitize(), - ..self - } - } -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct FavoriteTreeNode { - node_id: String, - label: String, - is_leaf: bool, - children: Option>, -} - -/// The software's configuration -/// include the version, backup's location path, games'info, -/// and the settings -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct Config { - pub version: String, - pub backup_path: String, - pub games: Vec, - pub settings: Settings, - #[serde(default = "default_value::empty_vec")] - pub favorites: Vec, -} - -impl Sanitizable for Config { - fn sanitize(self) -> Self { - Config { - settings: self.settings.sanitize(), - ..self - } - } -} - -impl Default for Config { - fn default() -> Self { - Config { - version: String::from("1.3.2"), - backup_path: String::from("./save_data"), - games: Vec::new(), - settings: Settings { - prompt_when_not_described: false, - extra_backup_when_apply: true, - show_edit_button: false, - prompt_when_auto_backup: true, - cloud_settings: default_value::default_cloud_settings(), - exit_to_tray: true, - locale: default_value::default_locale(), - default_delete_before_apply: false, - default_expend_favorites_tree: false, - home_page: default_value::default_home_page(), - log_to_file: true, - add_new_to_favorites: false, - }, - favorites: vec![], - } - } -} - -/// Set settings to original state -pub async fn reset_settings() -> Result<(), ConfigError> { - let settings = Config::default().settings; - let mut config = get_config()?; - config.settings = settings; - set_config(&config).await -} - -/// Create a config file -fn init_config() -> Result<(), ConfigError> { - info!("Init config file."); - fs::write( - "./GameSaveManager.config.json", - serde_json::to_string_pretty(&Config::default())?, - )?; - Ok(()) -} - -/// Get the current config file -pub fn get_config() -> Result { - let file = File::open("./GameSaveManager.config.json")?; - Ok(serde_json::from_reader(file)?) -} - -/// Replace the config file with a new config struct -pub async fn set_config(config: &Config) -> Result<(), ConfigError> { - fs::write( - "./GameSaveManager.config.json", - serde_json::to_string_pretty(&config)?, - )?; - // 处理云同步,上传新的配置文件 - if config.settings.cloud_settings.always_sync { - let op = config.settings.cloud_settings.backend.get_op()?; - crate::cloud::upload_config(&op).await?; - } - Ok(()) -} - -/// Check the config file exists or not -/// if not, then create one -/// then send the config to the front end -pub fn config_check() -> Result<(), ConfigError> { - let config_path = path::Path::new("./GameSaveManager.config.json"); - if !config_path.is_file() || !config_path.exists() { - init_config()?; - } - let mut config = get_config()?; - - // 处理早期版本兼容性 - if config.version == "1.0.0 alpha" { - "1.0.0-alpha".clone_into(&mut config.version); - } - let software_version = Version::parse(&Config::default().version)?; - let config_version = Version::parse(&config.version)?; - if config_version != software_version { - Notification::new("Update Config Info") - .title(t!("backend.config.updating_config_title")) - .body(t!("backend.config.updating_config_body")) - .show() - .expect("Cannot show notification"); - backup_old_config()?; - } - if config_version < Version::parse("1.0.0")? { - panic!("The config version is not supported.It's too old.") - } - if config_version < software_version { - upgrade_config_version(&mut config, &software_version)?; - } - if config_version > software_version { - panic!("The config version is higher than the software.") - } - - rust_i18n::set_locale(&config.settings.locale); - Ok(()) // return the config json -} - -fn upgrade_config_version( - config: &mut Config, - software_version: &semver::Version, -) -> Result<(), ConfigError> { - // 由于1.0之后版本保持了兼容性,因此不需要做任何处理,仅更新版本号并保存 - config.version = software_version.to_string(); - tauri::async_runtime::block_on(async { set_config(config).await })?; - Ok(()) -} - -fn backup_old_config() -> Result<(), ConfigError> { - fs::copy( - "./GameSaveManager.config.json", - "./GameSaveManager.config.json.bak", - )?; - Ok(()) -} - -#[cfg(test)] -mod test { - use super::Config; - use anyhow::Result; - - #[test] - fn serialize_default_config() -> Result<()> { - let config = Config::default(); - let json = serde_json::to_string_pretty(&config)?; - println!("序列化得到:\n{}", json); - Ok(()) - } -} diff --git a/src-tauri/src/config/config.rs b/src-tauri/src/config/config.rs new file mode 100644 index 0000000..0e0ea29 --- /dev/null +++ b/src-tauri/src/config/config.rs @@ -0,0 +1,62 @@ +use serde::{Deserialize, Serialize}; + +use crate::backup::Game; +use crate::default_value; +use crate::traits::Sanitizable; + +use super::Settings; + +/// The software's configuration +/// include the version, backup's location path, games'info, +/// and the settings +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Config { + pub version: String, + pub backup_path: String, + pub games: Vec, + pub settings: Settings, + #[serde(default = "default_value::empty_vec")] + pub favorites: Vec, +} + +impl Sanitizable for Config { + fn sanitize(self) -> Self { + Config { + settings: self.settings.sanitize(), + ..self + } + } +} + +impl Default for Config { + fn default() -> Self { + Config { + version: String::from("1.3.2"), + backup_path: String::from("./save_data"), + games: Vec::new(), + settings: Settings { + prompt_when_not_described: false, + extra_backup_when_apply: true, + show_edit_button: false, + prompt_when_auto_backup: true, + cloud_settings: default_value::default_cloud_settings(), + exit_to_tray: true, + locale: default_value::default_locale(), + default_delete_before_apply: false, + default_expend_favorites_tree: false, + home_page: default_value::default_home_page(), + log_to_file: true, + add_new_to_favorites: false, + }, + favorites: vec![], + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct FavoriteTreeNode { + node_id: String, + label: String, + is_leaf: bool, + children: Option>, +} diff --git a/src-tauri/src/config/mod.rs b/src-tauri/src/config/mod.rs new file mode 100644 index 0000000..1ea0b33 --- /dev/null +++ b/src-tauri/src/config/mod.rs @@ -0,0 +1,7 @@ +mod config; +mod settings; +mod utils; + +pub use config::Config; +pub use settings::Settings; +pub use utils::*; diff --git a/src-tauri/src/config/settings.rs b/src-tauri/src/config/settings.rs new file mode 100644 index 0000000..c0d5ec1 --- /dev/null +++ b/src-tauri/src/config/settings.rs @@ -0,0 +1,44 @@ +use serde::{Deserialize, Serialize}; + +use crate::cloud_sync::CloudSettings; +use crate::traits::Sanitizable; +use crate::default_value; + +/// Settings that can be configured by user +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Settings { + #[serde(default = "default_value::default_true")] + pub prompt_when_not_described: bool, + #[serde(default = "default_value::default_true")] + pub extra_backup_when_apply: bool, + #[serde(default = "default_value::default_false")] + pub show_edit_button: bool, + #[serde(default = "default_value::default_true")] + pub prompt_when_auto_backup: bool, + #[serde(default = "default_value::default_true")] + pub exit_to_tray: bool, + #[serde(default = "default_value::default_cloud_settings")] + pub cloud_settings: CloudSettings, + #[serde(default = "default_value::default_locale")] + pub locale: String, + #[serde(default = "default_value::default_false")] + pub default_delete_before_apply: bool, + #[serde(default = "default_value::default_false")] + pub default_expend_favorites_tree: bool, + #[serde(default = "default_value::default_home_page")] + pub home_page: String, + #[serde(default = "default_value::default_true")] + pub log_to_file: bool, + #[serde(default = "default_value::default_false")] + pub add_new_to_favorites: bool, +} + +impl Sanitizable for Settings { + fn sanitize(self) -> Self { + Settings { + cloud_settings: self.cloud_settings.sanitize(), + ..self + } + } +} + diff --git a/src-tauri/src/config/utils.rs b/src-tauri/src/config/utils.rs new file mode 100644 index 0000000..ddfc8d3 --- /dev/null +++ b/src-tauri/src/config/utils.rs @@ -0,0 +1,104 @@ +use std::fs::File; +use std::{fs, path}; + +use rust_i18n::t; +use semver::Version; +use tauri::api::notification::Notification; +use tracing::info; + +use super::Config; +use crate::errors::ConfigError; + +/// Set settings to original state +pub async fn reset_settings() -> Result<(), ConfigError> { + let settings = Config::default().settings; + let mut config = get_config()?; + config.settings = settings; + set_config(&config).await +} + +/// Create a config file +fn init_config() -> Result<(), ConfigError> { + info!("Init config file."); + fs::write( + "./GameSaveManager.config.json", + serde_json::to_string_pretty(&Config::default())?, + )?; + Ok(()) +} + +/// Get the current config file +pub fn get_config() -> Result { + let file = File::open("./GameSaveManager.config.json")?; + Ok(serde_json::from_reader(file)?) +} + +/// Replace the config file with a new config struct +pub async fn set_config(config: &Config) -> Result<(), ConfigError> { + fs::write( + "./GameSaveManager.config.json", + serde_json::to_string_pretty(&config)?, + )?; + // 处理云同步,上传新的配置文件 + if config.settings.cloud_settings.always_sync { + let op = config.settings.cloud_settings.backend.get_op()?; + crate::cloud_sync::upload_config(&op).await?; + } + Ok(()) +} + +/// Check the config file exists or not +/// if not, then create one +/// then send the config to the front end +pub fn config_check() -> Result<(), ConfigError> { + let config_path = path::Path::new("./GameSaveManager.config.json"); + if !config_path.is_file() || !config_path.exists() { + init_config()?; + } + let mut config = get_config()?; + + // 处理早期版本兼容性 + if config.version == "1.0.0 alpha" { + "1.0.0-alpha".clone_into(&mut config.version); + } + let software_version = Version::parse(&Config::default().version)?; + let config_version = Version::parse(&config.version)?; + if config_version != software_version { + Notification::new("Update Config Info") + .title(t!("backend.config.updating_config_title")) + .body(t!("backend.config.updating_config_body")) + .show() + .expect("Cannot show notification"); + backup_old_config()?; + } + if config_version < Version::parse("1.0.0")? { + panic!("The config version is not supported.It's too old.") + } + if config_version < software_version { + upgrade_config_version(&mut config, &software_version)?; + } + if config_version > software_version { + panic!("The config version is higher than the software.") + } + + rust_i18n::set_locale(&config.settings.locale); + Ok(()) // return the config json +} + +fn upgrade_config_version( + config: &mut Config, + software_version: &semver::Version, +) -> Result<(), ConfigError> { + // 由于1.0之后版本保持了兼容性,因此不需要做任何处理,仅更新版本号并保存 + config.version = software_version.to_string(); + tauri::async_runtime::block_on(async { set_config(config).await })?; + Ok(()) +} + +fn backup_old_config() -> Result<(), ConfigError> { + fs::copy( + "./GameSaveManager.config.json", + "./GameSaveManager.config.json.bak", + )?; + Ok(()) +} diff --git a/src-tauri/src/default_value.rs b/src-tauri/src/default_value.rs index 69319a3..d388293 100644 --- a/src-tauri/src/default_value.rs +++ b/src-tauri/src/default_value.rs @@ -1,4 +1,4 @@ -use crate::cloud::{Backend, CloudSettings}; +use crate::cloud_sync::{Backend, CloudSettings}; pub fn default_false() -> bool { false diff --git a/src-tauri/src/ipc_handler.rs b/src-tauri/src/ipc_handler.rs index 4ae19a8..e2e3ff8 100644 --- a/src-tauri/src/ipc_handler.rs +++ b/src-tauri/src/ipc_handler.rs @@ -1,6 +1,6 @@ -use crate::backup::BackupListInfo; -use crate::cloud::{self, upload_all, Backend}; -use crate::config::{get_config, Config, Game}; +use crate::backup::{Game, GameSnapshots}; +use crate::cloud_sync::{self, upload_all, Backend}; +use crate::config::{get_config, Config}; use crate::traits::Sanitizable; use crate::{backup, config}; use crate::{errors::*, tray}; @@ -90,10 +90,14 @@ pub async fn add_game(game: Game) -> Result<(), String> { #[allow(unused)] #[tauri::command] -pub async fn apply_backup(game: Game, date: String, app_handle: AppHandle) -> Result<(), String> { - //handle_backup_err(game.apply_backup(&date,window), ) +pub async fn restore_snapshot( + game: Game, + date: String, + app_handle: AppHandle, +) -> Result<(), String> { + //handle_backup_err(game.restore_snapshot(&date,window), ) info!(target:"rgsm::ipc", "Applying backup: {:?} for game: {:?}", date, game); - game.apply_backup(&date, &app_handle).map_err(|e| { + game.restore_snapshot(&date, &app_handle).map_err(|e| { error!(target:"rgsm::ipc", "Failed to apply backup: {:?}", e); e.to_string() })?; @@ -103,9 +107,9 @@ pub async fn apply_backup(game: Game, date: String, app_handle: AppHandle) -> Re #[allow(unused)] #[tauri::command] -pub async fn delete_backup(game: Game, date: String) -> Result<(), String> { +pub async fn delete_snapshot(game: Game, date: String) -> Result<(), String> { info!(target:"rgsm::ipc", "Deleting backup: {:?} for game: {:?}", date, game); - game.delete_backup(&date).await.map_err(|e| { + game.delete_snapshot(&date).await.map_err(|e| { error!(target:"rgsm::ipc", "Failed to delete backup: {:?}", e); e.to_string() })?; @@ -127,9 +131,9 @@ pub async fn delete_game(game: Game) -> Result<(), String> { #[allow(unused)] #[tauri::command] -pub async fn get_backup_list_info(game: Game) -> Result { +pub async fn get_game_snapshots_info(game: Game) -> Result { info!(target:"rgsm::ipc", "Getting backup list info for game: {:?}", game); - game.get_backup_list_info().map_err(|e| { + game.get_game_snapshots_info().map_err(|e| { error!(target:"rgsm::ipc", "Failed to get backup list info: {:?}", e); e.to_string() }) @@ -157,9 +161,9 @@ pub async fn reset_settings() -> Result<(), String> { #[allow(unused)] #[tauri::command] -pub async fn backup_save(game: Game, describe: String, window: Window) -> Result<(), String> { +pub async fn create_snapshot(game: Game, describe: String, window: Window) -> Result<(), String> { info!(target:"rgsm::ipc", "Backing up save for game: {:?}", game); - handle_backup_err(game.backup_save(&describe).await, window)?; + handle_backup_err(game.create_snapshot(&describe).await, window)?; info!(target:"rgsm::ipc", "Successfully backed up save for game: {:?}", game); Ok(()) } @@ -220,7 +224,7 @@ pub async fn cloud_download_all(backend: Backend) -> Result<(), String> { error!(target:"rgsm::ipc", "Failed to get cloud backend operator: {:?}", e); e.to_string() })?; - match cloud::download_all(&op).await { + match cloud_sync::download_all(&op).await { Ok(_) => { info!(target:"rgsm::ipc", "Successfully downloaded all backups from cloud backend: {:?}", backend.sanitize()); Ok(()) @@ -234,9 +238,13 @@ pub async fn cloud_download_all(backend: Backend) -> Result<(), String> { #[allow(unused)] #[tauri::command] -pub async fn set_backup_describe(game: Game, date: String, describe: String) -> Result<(), String> { +pub async fn set_snapshot_description( + game: Game, + date: String, + describe: String, +) -> Result<(), String> { info!(target:"rgsm::ipc", "Setting backup describe for game: {:?}", game); - game.set_backup_describe(&date, &describe) + game.set_snapshot_description(&date, &describe) .await .map_err(|e| { error!(target:"rgsm::ipc", "Failed to set backup describe: {:?}", e); diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 0921d7e..534cbc9 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -17,9 +17,8 @@ use tracing_subscriber::{filter::LevelFilter, Layer}; use crate::config::config_check; -mod archive; mod backup; -mod cloud; +mod cloud_sync; mod config; mod default_value; mod errors; @@ -47,18 +46,18 @@ fn main() { ipc_handler::choose_save_dir, ipc_handler::get_local_config, ipc_handler::add_game, - ipc_handler::apply_backup, - ipc_handler::delete_backup, + ipc_handler::restore_snapshot, + ipc_handler::delete_snapshot, ipc_handler::delete_game, - ipc_handler::get_backup_list_info, + ipc_handler::get_game_snapshots_info, ipc_handler::set_config, ipc_handler::reset_settings, - ipc_handler::backup_save, + ipc_handler::create_snapshot, ipc_handler::open_backup_folder, ipc_handler::check_cloud_backend, ipc_handler::cloud_upload_all, ipc_handler::cloud_download_all, - ipc_handler::set_backup_describe, + ipc_handler::set_snapshot_description, ipc_handler::backup_all, ipc_handler::apply_all, ipc_handler::set_quick_backup_game, @@ -116,7 +115,10 @@ fn init_log(config: &Config) { .with_ansi(false) .with_filter(LevelFilter::INFO); - tracing_subscriber::registry().with(console_layer).with(file_layer).init(); + tracing_subscriber::registry() + .with(console_layer) + .with(file_layer) + .init(); } else { tracing_subscriber::registry().with(console_layer).init(); }; diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs index 1fab81c..88b3f0b 100644 --- a/src-tauri/src/tray.rs +++ b/src-tauri/src/tray.rs @@ -10,7 +10,7 @@ use tauri::{ }; use tracing::{info, warn}; -use crate::config::{get_config, Game}; +use crate::{backup::Game, config::get_config}; use rust_i18n::t; @@ -70,7 +70,10 @@ pub fn get_tray() -> SystemTray { t!("backend.tray.quick_apply"), )) .add_native_item(SystemTrayMenuItem::Separator) - .add_item(CustomMenuItem::new("quit".to_owned(), t!("backend.tray.exit"))); + .add_item(CustomMenuItem::new( + "quit".to_owned(), + t!("backend.tray.exit"), + )); // Menu items end SystemTray::new().with_menu(tray_menu) @@ -114,7 +117,7 @@ pub fn tray_event_handler(app: &AppHandle, event: SystemTrayEvent) { Some(game) => { info!(target:"rgsm::tray", "Quick backup game: {:#?}", game); tauri::async_runtime::block_on(async { - game.backup_save("Quick Backup").await + game.create_snapshot("Quick Backup").await }) .expect("Tauri async runtime error, cannot block_on"); Notification::new(&app.config().tauri.bundle.identifier) @@ -146,7 +149,7 @@ pub fn tray_event_handler(app: &AppHandle, event: SystemTrayEvent) { Some(game) => { info!(target:"rgsm::tray", "Quick apply game: {:#?}", game); let newest_date = game - .get_backup_list_info() + .get_game_snapshots_info() .expect("Cannot get backup list info") .backups .last() @@ -154,7 +157,7 @@ pub fn tray_event_handler(app: &AppHandle, event: SystemTrayEvent) { .date .clone(); tauri::async_runtime::block_on(async { - game.apply_backup(&newest_date, app) + game.restore_snapshot(&newest_date, app) }) .expect("Tauri async runtime error, cannot block_on"); Notification::new(&app.config().tauri.bundle.identifier) @@ -243,7 +246,7 @@ pub fn setup_timer(app: &mut App) -> Result<(), Box> { .expect("Cannot get config") .settings .prompt_when_auto_backup; - game.backup_save("Auto Backup Info") + game.create_snapshot("Auto Backup Info") .await .expect("Cannot backup"); if show_info { diff --git a/src/views/GameManage.vue b/src/views/GameManage.vue index 4a87d0a..49f308d 100644 --- a/src/views/GameManage.vue +++ b/src/views/GameManage.vue @@ -45,9 +45,9 @@ let apply_button_apply_limit = true; // 上次未恢复好禁止读取或备份 let showEditButton = config.settings.show_edit_button; // 批量操作记录列表 -const selected_backup_list: Ref = ref([]); +const selected_game_snapshots: Ref = ref([]); function on_selection_change(val: Backup[]) { - selected_backup_list.value = val; + selected_game_snapshots.value = val; } async function batch_delete() { try { @@ -63,7 +63,7 @@ async function batch_delete() { ); if (result.value === 'yes') { - for (const item of selected_backup_list.value) { + for (const item of selected_game_snapshots.value) { await del_save(item.date); } } else { @@ -88,7 +88,7 @@ watch( ) function refresh_backups_info() { - invoke("get_backup_list_info", { game: game.value }) + invoke("get_game_snapshots_info", { game: game.value }) .then((v) => { let infos = v as BackupsInfo; table_data.value = infos.backups; @@ -96,7 +96,7 @@ function refresh_backups_info() { }).catch( (e) => { console.log(e) - show_error($t('error.get_backup_list_failed')); + show_error($t('error.get_game_snapshots_failed')); } ) } @@ -117,7 +117,7 @@ function send_save_to_background() { } backup_button_time_limit = false; backup_button_backup_limit = false; - invoke("backup_save", { game: game.value, describe: describe.value }) + invoke("create_snapshot", { game: game.value, describe: describe.value }) .then((_) => { show_success($t('manage.backup_success')); }).catch( @@ -175,13 +175,13 @@ function launch_game() { async function del_save(date: string) { try { console.log(date); - const result = await invoke("delete_backup", { game: game.value, date: date }); + const result = await invoke("delete_snapshot", { game: game.value, date: date }); console.log(result); refresh_backups_info(); show_success($t('manage.delete_success')); } catch (e) { console.log(e); - show_error($t('error.delete_backup_failed')); + show_error($t('error.delete_snapshot_failed')); } } @@ -197,13 +197,13 @@ function apply_save(date: string) { return; } apply_button_apply_limit = false; - invoke("apply_backup", { game: game.value, date: date }) + invoke("restore_snapshot", { game: game.value, date: date }) .then((x) => { show_success($t('manage.recover_success')); console.log(x) }).catch((e) => { console.log(e) - show_error($t('error.apply_backup_failed')) + show_error($t('error.restore_snapshot_failed')) }).finally(() => { info.close() apply_button_apply_limit = true; @@ -218,7 +218,7 @@ function change_describe(date: string) { inputValue: table_data.value.find((x) => x.date == date)?.describe, }) .then(({ value }) => { - invoke("set_backup_describe", { game: game.value, date: date, describe: value }) + invoke("set_snapshot_description", { game: game.value, date: date, describe: value }) .then((x) => { console.log(x) refresh_backups_info(); @@ -363,7 +363,7 @@ const filter_table = computed( {{ $t('manage.delete_save_manage') }} - + {{ $t("manage.batch_delete") }} From e3e353bf79c96046867fdb8f5404dc62b8f52180 Mon Sep 17 00:00:00 2001 From: Sworld <61224072+mcthesw@users.noreply.github.com> Date: Sat, 28 Sep 2024 00:51:36 +0800 Subject: [PATCH 02/11] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=BC=BA=E5=A4=87?= =?UTF-8?q?=E4=BB=BD=E5=92=8C=E6=81=A2=E5=A4=8D=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=85=8D=E7=BD=AE=E5=92=8C=E6=89=98=E7=9B=98?= =?UTF-8?q?=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 本次提交增强了备份和恢复功能,重构了配置和托盘菜单,并进行了一些其他改进: - 添加了对全局快捷键的支持。 - 修复了备份和恢复操作中的路径处理错误。 - 完善了备份和恢复过程中的错误处理和警告信息。 - 允许在没有 AppHandle 的情况下进行备份和恢复操作。 - 允许在没有 AppHandle 的情况下应用所有备份。 - 重构了配置文件结构。 - 重构了托盘菜单代码和逻辑。 - 改进了错误处理和错误信息。 - 更新了默认语言设置。 - 优化了日志信息。 --- src-tauri/Cargo.toml | 1 + src-tauri/src/backup/archive.rs | 23 +- src-tauri/src/backup/game.rs | 23 +- src-tauri/src/backup/utils.rs | 2 +- src-tauri/src/cloud_sync/cloud_settings.rs | 11 + .../src/config/{config.rs => app_config.rs} | 7 +- src-tauri/src/config/mod.rs | 6 +- .../src/config/quick_actions_settings.rs | 17 ++ src-tauri/src/config/settings.rs | 3 +- src-tauri/src/default_value.rs | 10 +- src-tauri/src/errors.rs | 46 +-- src-tauri/src/ipc_handler.rs | 35 ++- src-tauri/src/main.rs | 13 +- src-tauri/src/quick_actions/hotkeys.rs | 0 src-tauri/src/quick_actions/mod.rs | 10 + src-tauri/src/quick_actions/timer.rs | 41 +++ src-tauri/src/quick_actions/tray.rs | 127 ++++++++ src-tauri/src/quick_actions/utils.rs | 114 +++++++ src-tauri/src/tray.rs | 280 ------------------ 19 files changed, 420 insertions(+), 349 deletions(-) rename src-tauri/src/config/{config.rs => app_config.rs} (87%) create mode 100644 src-tauri/src/config/quick_actions_settings.rs create mode 100644 src-tauri/src/quick_actions/hotkeys.rs create mode 100644 src-tauri/src/quick_actions/mod.rs create mode 100644 src-tauri/src/quick_actions/timer.rs create mode 100644 src-tauri/src/quick_actions/tray.rs create mode 100644 src-tauri/src/quick_actions/utils.rs delete mode 100644 src-tauri/src/tray.rs diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index ba76ad2..1581513 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -21,6 +21,7 @@ tauri = { version = "1.6.8", features = [ "dialog", "system-tray", "notification", + "global-shortcut", ] } anyhow = "1.0.69" chrono = "0.4.23" diff --git a/src-tauri/src/backup/archive.rs b/src-tauri/src/backup/archive.rs index afdea0a..56cb779 100644 --- a/src-tauri/src/backup/archive.rs +++ b/src-tauri/src/backup/archive.rs @@ -6,8 +6,8 @@ use std::{ use fs_extra::dir::move_dir; use fs_extra::file::move_file; - use tauri::{AppHandle, Manager}; +use tracing::warn; use zip::{write::SimpleFileOptions, ZipWriter}; use crate::{ @@ -52,7 +52,7 @@ where let entry_path = entry.path(); let entry_metadata = fs::metadata(&entry_path)?; let mut cur_path = prefix_path.to_path_buf(); - cur_path = cur_path.join(&entry.file_name()); + cur_path = cur_path.join(entry.file_name()); if entry_metadata.is_file() { let mut f = File::open(&entry_path)?; f.read_to_end(&mut buffer)?; @@ -125,7 +125,7 @@ pub fn decompress_from_file( save_paths: &[SaveUnit], backup_path: &Path, date: &str, - app_handle: &AppHandle, + app_handle: Option<&AppHandle>, ) -> Result<(), CompressError> { let zip_path = backup_path.join([date, ".zip"].concat()); let file = File::open(zip_path).map_err(|e| CompressError::Single(e.into()))?; @@ -153,7 +153,11 @@ pub fn decompress_from_file( unit_path.parent().ok_or(BackupFileError::NonePathError)?; if !prefix_root.exists() { // 若文件夹不存在,需要发出警告 - app_handle + warn!(target:"rgsm::backup::archive","Path {:#?} not exists, auto created",prefix_root + .to_str() + .unwrap_or("prefix_root.to_str error")); + if let Some(app_handle) = app_handle { + app_handle .emit_all( "Notification", IpcNotification { @@ -169,6 +173,10 @@ pub fn decompress_from_file( }, ) .map_err(anyhow::Error::from)?; + }else { + // TODO:发出警告? + } + fs::create_dir_all(prefix_root)?; } if unit.delete_before_apply && unit_path.exists() { @@ -182,6 +190,10 @@ pub fn decompress_from_file( unit_path.parent().ok_or(BackupFileError::NonePathError)?; if !target_path.exists() { // 若文件夹不存在,需要发出警告 + warn!(target:"rgsm::backup::archive","Path {:#?} not exists, auto created",target_path + .to_str() + .unwrap_or("prefix_root.to_str error")); + if let Some(app_handle) = app_handle { app_handle .emit_all( "Notification", @@ -198,6 +210,9 @@ pub fn decompress_from_file( }, ) .map_err(anyhow::Error::from)?; + }else{ + // TODO:发出警告? + } fs::create_dir_all(target_path)?; } if unit.delete_before_apply && unit_path.exists() { diff --git a/src-tauri/src/backup/game.rs b/src-tauri/src/backup/game.rs index 7e50af0..7527cd6 100644 --- a/src-tauri/src/backup/game.rs +++ b/src-tauri/src/backup/game.rs @@ -1,12 +1,11 @@ use serde::{Deserialize, Serialize}; +use tauri::AppHandle; use crate::cloud_sync::{upload_config, upload_game_snapshots}; use crate::config::{get_config, set_config}; use crate::errors::BackupError; -use crate::ipc_handler::{IpcNotification, NotificationLevel}; use std::path::PathBuf; use std::{fs, path}; -use tauri::{AppHandle, Manager}; use tracing::{error, info}; use super::GameSnapshots; @@ -54,7 +53,7 @@ impl Game { if let Err(e) = compress_to_file(save_paths, &zip_path) { // delete the zip if failed to write fs::remove_file(&zip_path)?; - return Err(BackupError::CompressError(e)); + return Err(BackupError::Compress(e)); } let game_snapshots_info = Snapshot { @@ -85,24 +84,18 @@ impl Game { } Result::Ok(()) } - pub fn restore_snapshot(&self, date: &str, app_handle: &AppHandle) -> Result<(), BackupError> { + pub fn restore_snapshot( + &self, + date: &str, + app_handle: Option<&AppHandle>, + ) -> Result<(), BackupError> { let config = get_config()?; let backup_path = path::Path::new(&config.backup_path).join(&self.name); if config.settings.extra_backup_when_apply { info!(target:"rgsm::backup::game","Creating extra backup."); if let Err(e) = self.create_overwrite_snapshot() { error!(target:"rgsm::backup::game","Failed to create extra backup: {:?}", e); - app_handle - .emit_all( - "Notification", - IpcNotification { - level: NotificationLevel::error, - title: "ERROR".to_string(), - msg: t!("backend.backup.extra_backup_file_not_exist").to_string(), - }, - ) - .map_err(anyhow::Error::from)?; - return Err(e); + return Err(BackupError::ExtraBackupFailed); } } decompress_from_file(&self.save_paths, &backup_path, date, app_handle)?; diff --git a/src-tauri/src/backup/utils.rs b/src-tauri/src/backup/utils.rs index 6b990c7..fcf6291 100644 --- a/src-tauri/src/backup/utils.rs +++ b/src-tauri/src/backup/utils.rs @@ -64,7 +64,7 @@ pub async fn backup_all() -> Result<(), BackupError> { } Ok(()) } -pub async fn apply_all(app_handle: &AppHandle) -> Result<(), BackupError> { +pub async fn apply_all(app_handle: Option<&AppHandle>) -> Result<(), BackupError> { let config = get_config()?; for game in &config.games { let date = game diff --git a/src-tauri/src/cloud_sync/cloud_settings.rs b/src-tauri/src/cloud_sync/cloud_settings.rs index b2eecf1..f96216e 100644 --- a/src-tauri/src/cloud_sync/cloud_settings.rs +++ b/src-tauri/src/cloud_sync/cloud_settings.rs @@ -21,6 +21,17 @@ pub struct CloudSettings { pub backend: Backend, } +impl Default for CloudSettings { + fn default() -> Self { + CloudSettings { + always_sync: false, + auto_sync_interval: 0, + root_path: "/game-save-manager".to_string(), + backend: Backend::Disabled, + } + } +} + impl Sanitizable for CloudSettings { fn sanitize(self) -> Self { CloudSettings { diff --git a/src-tauri/src/config/config.rs b/src-tauri/src/config/app_config.rs similarity index 87% rename from src-tauri/src/config/config.rs rename to src-tauri/src/config/app_config.rs index 0e0ea29..b76ad32 100644 --- a/src-tauri/src/config/config.rs +++ b/src-tauri/src/config/app_config.rs @@ -1,10 +1,11 @@ use serde::{Deserialize, Serialize}; use crate::backup::Game; +use crate::cloud_sync::CloudSettings; use crate::default_value; use crate::traits::Sanitizable; -use super::Settings; +use super::{QuickActionsSettings, Settings}; /// The software's configuration /// include the version, backup's location path, games'info, @@ -17,6 +18,7 @@ pub struct Config { pub settings: Settings, #[serde(default = "default_value::empty_vec")] pub favorites: Vec, + pub quick_action: QuickActionsSettings, } impl Sanitizable for Config { @@ -39,7 +41,7 @@ impl Default for Config { extra_backup_when_apply: true, show_edit_button: false, prompt_when_auto_backup: true, - cloud_settings: default_value::default_cloud_settings(), + cloud_settings: CloudSettings::default(), exit_to_tray: true, locale: default_value::default_locale(), default_delete_before_apply: false, @@ -49,6 +51,7 @@ impl Default for Config { add_new_to_favorites: false, }, favorites: vec![], + quick_action: QuickActionsSettings::default(), } } } diff --git a/src-tauri/src/config/mod.rs b/src-tauri/src/config/mod.rs index 1ea0b33..63abd11 100644 --- a/src-tauri/src/config/mod.rs +++ b/src-tauri/src/config/mod.rs @@ -1,7 +1,9 @@ -mod config; +mod app_config; +mod quick_actions_settings; mod settings; mod utils; -pub use config::Config; +pub use app_config::Config; +pub use quick_actions_settings::{QuickActions, QuickActionsSettings}; pub use settings::Settings; pub use utils::*; diff --git a/src-tauri/src/config/quick_actions_settings.rs b/src-tauri/src/config/quick_actions_settings.rs new file mode 100644 index 0000000..b07256a --- /dev/null +++ b/src-tauri/src/config/quick_actions_settings.rs @@ -0,0 +1,17 @@ +use serde::{Deserialize, Serialize}; + +use crate::{backup::Game, default_value}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub enum QuickActions { + Apply, + Backup, +} + +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +pub struct QuickActionsSettings { + #[serde(default = "default_value::default_none")] + pub quick_action_game: Option, + #[serde(default = "default_value::empty_vec")] + pub hotkeys: Vec<(String, QuickActions)>, +} diff --git a/src-tauri/src/config/settings.rs b/src-tauri/src/config/settings.rs index c0d5ec1..32cf31e 100644 --- a/src-tauri/src/config/settings.rs +++ b/src-tauri/src/config/settings.rs @@ -1,8 +1,8 @@ use serde::{Deserialize, Serialize}; use crate::cloud_sync::CloudSettings; -use crate::traits::Sanitizable; use crate::default_value; +use crate::traits::Sanitizable; /// Settings that can be configured by user #[derive(Debug, Serialize, Deserialize, Clone)] @@ -41,4 +41,3 @@ impl Sanitizable for Settings { } } } - diff --git a/src-tauri/src/default_value.rs b/src-tauri/src/default_value.rs index d388293..0de7557 100644 --- a/src-tauri/src/default_value.rs +++ b/src-tauri/src/default_value.rs @@ -19,12 +19,7 @@ pub fn default_backend() -> Backend { Backend::Disabled } pub fn default_cloud_settings() -> CloudSettings { - CloudSettings { - always_sync: false, - auto_sync_interval: 0, - root_path: "/game-save-manager".to_string(), - backend: Backend::Disabled, - } + CloudSettings::default() } pub fn default_locale() -> String { "zh_SIMPLIFIED".to_owned() @@ -32,3 +27,6 @@ pub fn default_locale() -> String { pub fn empty_vec() -> Vec { Vec::new() } +pub fn default_none() -> Option { + None +} diff --git a/src-tauri/src/errors.rs b/src-tauri/src/errors.rs index ab10ea8..5223f8d 100644 --- a/src-tauri/src/errors.rs +++ b/src-tauri/src/errors.rs @@ -8,9 +8,9 @@ pub enum BackupFileError { #[error("File to backup not exists: {0:#?}")] NotExists(PathBuf), #[error("Cannot write zip file: {0:#?}")] - ZipError(#[from] zip::result::ZipError), + Zip(#[from] zip::result::ZipError), #[error("Fs_extra error: {0:#?}")] - FsError(#[from] fs_extra::error::Error), + Fs(#[from] fs_extra::error::Error), #[error("Cannot convert path to string")] NonePathError, #[error(transparent)] @@ -33,21 +33,21 @@ pub enum BackendError { #[error("Backend is disabled")] Disabled, #[error("IO error: {0:#?}")] - IoError(#[from] io::Error), + Io(#[from] io::Error), #[error("Opendal error: {0:#?}")] - CloudError(#[from] opendal::Error), + Cloud(#[from] opendal::Error), #[error("Cannot read cloud file: {0:#?}")] - ReadCloudInfoError(#[from] FromUtf8Error), + ReadCloudInfo(#[from] FromUtf8Error), #[error("Deserialize error: {0:#?}")] - DeserializeError(#[from] serde_json::Error), + Deserialize(#[from] serde_json::Error), #[error(transparent)] Unexpected(#[from] anyhow::Error), } impl From for BackendError { fn from(e: ConfigError) -> Self { match e { - ConfigError::IoError(e) => Self::IoError(e), - ConfigError::DeserializeError(e) => Self::DeserializeError(e), + ConfigError::Io(e) => Self::Io(e), + ConfigError::Deserialize(e) => Self::Deserialize(e), other => Self::Unexpected(other.into()), } } @@ -55,8 +55,8 @@ impl From for BackendError { impl From for BackendError { fn from(e: BackupError) -> Self { match e { - BackupError::IoError(e) => Self::IoError(e), - BackupError::DeserializeError(e) => Self::DeserializeError(e), + BackupError::Io(e) => Self::Io(e), + BackupError::Deserialize(e) => Self::Deserialize(e), other => Self::Unexpected(other.into()), } } @@ -69,28 +69,30 @@ pub enum BackupError { #[error("No backups available")] NoBackupAvailable, #[error("Backend error: {0:#?}")] - BackendError(#[from] BackendError), + Backend(#[from] BackendError), #[error("Compress/Decompress error: {0:#?}")] - CompressError(#[from] CompressError), + Compress(#[from] CompressError), #[error("Deserialize error: {0:#?}")] - DeserializeError(#[from] serde_json::Error), + Deserialize(#[from] serde_json::Error), #[error("Cannot convert path to string")] NonePathError, #[error("IO error: {0:#?}")] - IoError(#[from] io::Error), + Io(#[from] io::Error), + #[error("Cannot create extra backup")] + ExtraBackupFailed, #[error(transparent)] Unexpected(#[from] anyhow::Error), } impl From for BackupError { fn from(e: opendal::Error) -> Self { - Self::BackendError(BackendError::CloudError(e)) + Self::Backend(BackendError::Cloud(e)) } } impl From for BackupError { fn from(e: ConfigError) -> Self { match e { - ConfigError::IoError(e) => Self::IoError(e), - ConfigError::DeserializeError(e) => Self::DeserializeError(e), + ConfigError::Io(e) => Self::Io(e), + ConfigError::Deserialize(e) => Self::Deserialize(e), other => Self::Unexpected(other.into()), } } @@ -99,13 +101,13 @@ impl From for BackupError { #[derive(Debug, Error)] pub enum ConfigError { #[error("Deserialize error: {0:#?}")] - DeserializeError(#[from] serde_json::Error), + Deserialize(#[from] serde_json::Error), #[error("IO error: {0:#?}")] - IoError(#[from] io::Error), + Io(#[from] io::Error), #[error("Backend error: {0:#?}")] - BackendError(#[from] BackendError), + Backend(#[from] BackendError), #[error("Tauri error: {0:#?}")] - TauriError(#[from] tauri::Error), + Tauri(#[from] tauri::Error), #[error("Semver error: {0:#?}")] - SemverError(#[from] semver::Error), + Semver(#[from] semver::Error), } diff --git a/src-tauri/src/ipc_handler.rs b/src-tauri/src/ipc_handler.rs index e2e3ff8..67d2916 100644 --- a/src-tauri/src/ipc_handler.rs +++ b/src-tauri/src/ipc_handler.rs @@ -1,16 +1,16 @@ use crate::backup::{Game, GameSnapshots}; use crate::cloud_sync::{self, upload_all, Backend}; use crate::config::{get_config, Config}; +use crate::errors::*; use crate::traits::Sanitizable; -use crate::{backup, config}; -use crate::{errors::*, tray}; +use crate::{backup, config, quick_actions}; use anyhow::Result; use rust_embed::Embed; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::PathBuf; use tauri::api::dialog; -use tauri::{AppHandle, Window}; +use tauri::{AppHandle, Manager, Window}; use tracing::{debug, error, info, warn}; #[allow(non_camel_case_types)] @@ -97,10 +97,25 @@ pub async fn restore_snapshot( ) -> Result<(), String> { //handle_backup_err(game.restore_snapshot(&date,window), ) info!(target:"rgsm::ipc", "Applying backup: {:?} for game: {:?}", date, game); - game.restore_snapshot(&date, &app_handle).map_err(|e| { - error!(target:"rgsm::ipc", "Failed to apply backup: {:?}", e); - e.to_string() - })?; + game.restore_snapshot(&date, Some(&app_handle)) + .map_err(|e| { + match &e { + BackupError::ExtraBackupFailed => { + app_handle.emit_all( + "Notification", + IpcNotification { + level: NotificationLevel::error, + title: "ERROR".to_string(), + msg: t!("backend.backup.extra_backup_file_not_exist").to_string(), + }, + ); + } + other => { + error!(target:"rgsm::ipc", "Failed to apply backup: {:?}", other); + } + } + e.to_string() + })?; info!(target:"rgsm::ipc", "Successfully applied backup: {:?} for game: {:?}", date, game); Ok(()) } @@ -270,7 +285,7 @@ pub async fn backup_all() -> Result<(), String> { #[tauri::command] pub async fn apply_all(app_handle: AppHandle) -> Result<(), String> { info!(target:"rgsm::ipc","Applying all backups."); - backup::apply_all(&app_handle).await.map_err(|e| { + backup::apply_all(Some(&app_handle)).await.map_err(|e| { error!(target:"rgsm::ipc", "Failed to apply all backups: {:?}", e); e.to_string() })?; @@ -282,7 +297,7 @@ pub async fn apply_all(app_handle: AppHandle) -> Result<(), String> { #[tauri::command] pub async fn set_quick_backup_game(app_handle: AppHandle, game: Game) -> Result<(), String> { info!(target:"rgsm::ipc","Setting quick backup game to: {:?}", game); - tray::set_current_game(&app_handle, game); + quick_actions::set_current_game(&app_handle, game); Ok(()) } @@ -331,7 +346,7 @@ pub async fn get_locale_message( fn handle_backup_err(res: Result<(), BackupError>, window: Window) -> Result<(), String> { if let Err(e) = res { match &e { - BackupError::CompressError(CompressError::Multiple(files)) => { + BackupError::Compress(CompressError::Multiple(files)) => { files.iter().for_each(|file| { error!(target:"rgsm::ipc","{}",file); if let BackupFileError::NotExists(path) = file { diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 534cbc9..63f10fa 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -23,8 +23,8 @@ mod config; mod default_value; mod errors; mod ipc_handler; +mod quick_actions; mod traits; -mod tray; fn main() { // Init config @@ -39,7 +39,10 @@ fn main() { // Init app let app = tauri::Builder::default() - .manage(Arc::new(Mutex::new(tray::QuickBackupState::default()))) + .manage(Arc::new(Mutex::new( + // 自动备份间隔,启动时默认为无(不自动备份) + quick_actions::AutoBackupDuration::new(0), + ))) .invoke_handler(tauri::generate_handler![ ipc_handler::open_url, ipc_handler::choose_save_file, @@ -69,9 +72,9 @@ fn main() { // 处理退出到托盘 if config.settings.exit_to_tray { - app.system_tray(tray::get_tray()) - .on_system_tray_event(tray::tray_event_handler) - .setup(tray::setup_timer) + app.system_tray(quick_actions::get_tray()) + .on_system_tray_event(quick_actions::tray_event_handler) + .setup(quick_actions::setup_timer) .build(tauri::generate_context!()) .expect("Cannot build tauri app") .run(|_app_handle, event| { diff --git a/src-tauri/src/quick_actions/hotkeys.rs b/src-tauri/src/quick_actions/hotkeys.rs new file mode 100644 index 0000000..e69de29 diff --git a/src-tauri/src/quick_actions/mod.rs b/src-tauri/src/quick_actions/mod.rs new file mode 100644 index 0000000..8cf0375 --- /dev/null +++ b/src-tauri/src/quick_actions/mod.rs @@ -0,0 +1,10 @@ +mod hotkeys; +mod timer; +mod tray; +mod utils; + +use utils::*; + +pub use timer::{setup_timer, AutoBackupDuration}; +pub use tray::{get_tray, tray_event_handler}; +pub use utils::set_current_game; diff --git a/src-tauri/src/quick_actions/timer.rs b/src-tauri/src/quick_actions/timer.rs new file mode 100644 index 0000000..549e888 --- /dev/null +++ b/src-tauri/src/quick_actions/timer.rs @@ -0,0 +1,41 @@ +use std::{ + sync::{atomic::AtomicU32, Arc}, + time::Duration, +}; + +use tauri::{App, Manager, State}; +use tracing::info; + +use super::{get_quick_action_game, quick_backup, QuickActionType}; + +pub type AutoBackupDuration = AtomicU32; + +pub fn setup_timer(app: &mut App) -> Result<(), Box> { + info!(target:"rgsm::quick_action::timer","Setting up tray timer."); + let state: State> = app.state(); + let state = state.inner().clone(); + tauri::async_runtime::spawn(async move { + let mut counter = 0; + let mut last = 0; + loop { + let duration = state.load(std::sync::atomic::Ordering::Relaxed); + let game = get_quick_action_game(); + if last != duration { + // 如果发生改变,重新计数 + counter = 1; + } + + if counter >= duration { + quick_backup(game, QuickActionType::Timer).await; + counter = 0; + } + + last = duration; + std::thread::sleep(Duration::from_secs(60)); + counter += 1; + counter %= u32::MAX; // 防止溢出 + } + }); + info!(target:"rgsm::quick_action::timer","Tray timer setup complete."); + Ok(()) +} diff --git a/src-tauri/src/quick_actions/tray.rs b/src-tauri/src/quick_actions/tray.rs new file mode 100644 index 0000000..3eee669 --- /dev/null +++ b/src-tauri/src/quick_actions/tray.rs @@ -0,0 +1,127 @@ +use std::sync::Arc; + +use tauri::{ + utils::config::WindowConfig, AppHandle, CustomMenuItem, + LogicalSize, Manager, State, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, + SystemTraySubmenu, +}; +use tracing::info; + +use crate::quick_actions::get_quick_action_game; + +use super::{quick_apply, quick_backup, AutoBackupDuration, QuickActionType}; + +use rust_i18n::t; + +// TODO:处理错误 +pub fn get_tray() -> SystemTray { + // Menu items begin + let tray_menu = SystemTrayMenu::new() + .add_item(CustomMenuItem::new( + "game".to_owned(), + t!("backend.tray.no_game_selected"), + )) + .add_submenu(SystemTraySubmenu::new( + t!("backend.tray.auto_backup_interval"), + SystemTrayMenu::new() + .add_item(CustomMenuItem::new( + "timer.0".to_owned(), + t!("backend.tray.turn_off_auto_backup"), + )) + .add_item(CustomMenuItem::new( + "timer.5".to_owned(), + t!("backend.tray.5_minute"), + )) + .add_item(CustomMenuItem::new( + "timer.10".to_owned(), + t!("backend.tray.10_minute"), + )) + .add_item(CustomMenuItem::new( + "timer.30".to_owned(), + t!("backend.tray.30_minute"), + )) + .add_item(CustomMenuItem::new( + "timer.60".to_owned(), + t!("backend.tray.60_minute"), + )), + )) + .add_item(CustomMenuItem::new( + "backup".to_owned(), + t!("backend.tray.quick_backup"), + )) + .add_item(CustomMenuItem::new( + "apply".to_owned(), + t!("backend.tray.quick_apply"), + )) + .add_native_item(SystemTrayMenuItem::Separator) + .add_item(CustomMenuItem::new( + "quit".to_owned(), + t!("backend.tray.exit"), + )); + // Menu items end + + SystemTray::new().with_menu(tray_menu) +} + +pub fn tray_event_handler(app: &AppHandle, event: SystemTrayEvent) { + match event { + SystemTrayEvent::LeftClick { .. } => { + info!(target: "rgsm::quick_action::tray", "Tray left click"); + if let Some(window) = app.get_window("main") { + window.close().expect("Cannot close window"); + } else { + let window = tauri::WindowBuilder::from_config( + app, + WindowConfig { + label: "main".to_string(), + url: tauri::WindowUrl::App("index.html".into()), + file_drop_enabled: false, // 必须这样设置,否则窗体内js接收不到drag & drop事件 + ..Default::default() + }, + ) + .build() + .unwrap(); + + window + .set_size(LogicalSize { + width: 1280.0, + height: 720.0, + }) + .expect("Cannot set size"); + window.show().expect("Cannot show window"); + window.set_focus().expect("Cannot set focus"); + } + } + SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() { + "backup" => { + info!(target:"rgsm::quick_action::tray", "Tray quick backup clicked"); + let game = get_quick_action_game(); + tauri::async_runtime::block_on(async { + quick_backup(game, QuickActionType::Tray).await + }); + } + "apply" => { + info!(target:"rgsm::quick_action::tray", "Tray quick apply clicked."); + let game = get_quick_action_game(); + tauri::async_runtime::block_on(async { + quick_apply(game, QuickActionType::Tray).await + }); + } + "quit" => { + info!(target:"rgsm::quick_action::tray","Tray quit clicked."); + app.exit(0); + } + other => { + // other情况一定是选择定时备份的时间 + info!(target:"rgsm::quick_action::tray","Tray menu item clicked: {other}."); + if other.starts_with("timer.") { + // safe:所有输入来自程序字面量,保证了不会出现非数字的情况 + let duration = other.split('.').last().unwrap().parse::().unwrap(); + let state: State> = app.state(); + state.store(duration, std::sync::atomic::Ordering::Relaxed); + } + } + }, + _ => {} + } +} diff --git a/src-tauri/src/quick_actions/utils.rs b/src-tauri/src/quick_actions/utils.rs new file mode 100644 index 0000000..7ffa125 --- /dev/null +++ b/src-tauri/src/quick_actions/utils.rs @@ -0,0 +1,114 @@ +use tauri::{api::notification::Notification, AppHandle}; +use tracing::{info, warn}; + +use crate::{ + backup::Game, + config::{get_config, set_config}, +}; + +pub fn set_current_game(app: &AppHandle, game: Game) { + info!(target:"rgsm::tray","Setting current quick backup game:{}",game.name); + app.tray_handle() + .get_item("game") + .set_title(&game.name) + .expect("Cannot get tray handle"); + let mut config = get_config().expect("Cannot get config"); + config.quick_action.quick_action_game = Some(game); + tauri::async_runtime::block_on(async { set_config(&config).await }).expect("Cannot set config"); +} + +#[derive(Debug, PartialEq)] +pub enum QuickActionType { + Timer, + Tray, + Hotkey, +} + +impl QuickActionType { + fn generate_describe(&self) -> String { + match &self { + QuickActionType::Timer => String::from("Auto Backup (Timer)"), + QuickActionType::Tray => String::from("Quick Backup (Tray)"), + QuickActionType::Hotkey => String::from("Quick Backup (Hotkey)"), + } + } +} + +pub async fn quick_apply(game: Option, t: QuickActionType) { + info!(target:"rgsm::quick_action", "Auto apply triggered: {:#?}",t.generate_describe()); + match game { + Some(game) => { + info!(target:"rgsm::quick_action", "Quick apply game: {:#?}", game); + let newest_date = game + .get_game_snapshots_info() + .expect("Cannot get backup list info") + .backups + .last() + .expect("No backup available") + .date + .clone(); + tauri::async_runtime::block_on(async { game.restore_snapshot(&newest_date, None) }) + .expect("Cannot restore save"); + Notification::new("QuickAction") + .title(t!("backend.tray.success")) + .body(format!( + "{:#?} {} {}", + game.name, + t!("backend.tray.quick_apply"), + t!("backend.tray.success") + )) + .show() + .expect("Cannot show notification"); + } + None => show_no_game_selected_error(), + } +} + +pub async fn quick_backup(game: Option, t: QuickActionType) { + info!(target:"rgsm::quick_action", "Auto backup triggered: {:#?}",t.generate_describe()); + // TODO:这里可以让match有返回值来判断是否出错 + match &game { + None => show_no_game_selected_error(), + Some(game) => { + let show_info = get_config() + .expect("Cannot get config") + .settings + .prompt_when_auto_backup; + game.create_snapshot(&t.generate_describe()) + .await + .expect("Cannot backup"); + if !show_info && (t == QuickActionType::Timer) { + // 设置中该选项控制是否在按间隔备份时发出通知 + // 若不启用,则不进行通知,其余情况则产生通知 + return; + } + Notification::new("QuickAction") + .title(t!("backend.tray.success")) + .body(format!( + "{:#?} {} {}", + game.name, + t!("backend.tray.quick_backup"), + t!("backend.tray.success") + )) + .show() + .expect("Cannot show notification"); + } + } +} + +fn show_no_game_selected_error() { + warn!(target:"rgsm::quick_action", "No game selected, cannot quick backup/apply"); + Notification::new("QuickAction") + .title(t!("backend.tray.error")) + .body(t!("backend.tray.no_game_selected")) + .show() + .expect("Cannot show notification"); +} + +pub fn get_quick_action_game() -> Option { + get_config() + .expect("Cannot get config") + .quick_action + .quick_action_game + .clone() +} diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs deleted file mode 100644 index 88b3f0b..0000000 --- a/src-tauri/src/tray.rs +++ /dev/null @@ -1,280 +0,0 @@ -use std::{ - sync::{Arc, Mutex}, - time::Duration, -}; - -use tauri::{ - api::notification::Notification, utils::config::WindowConfig, App, AppHandle, CustomMenuItem, - LogicalSize, Manager, State, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, - SystemTraySubmenu, -}; -use tracing::{info, warn}; - -use crate::{backup::Game, config::get_config}; - -use rust_i18n::t; - -#[derive(Debug, serde::Serialize, serde::Deserialize)] -pub struct QuickBackupState { - pub current_game: Option, - /// 自动备份的间隔,以分钟为单位 - pub auto_backup_duration: Option, -} -impl QuickBackupState { - pub fn default() -> QuickBackupState { - QuickBackupState { - current_game: None, - auto_backup_duration: None, - } - } -} - -// TODO:处理错误 -pub fn get_tray() -> SystemTray { - // Menu items begin - let tray_menu = SystemTrayMenu::new() - .add_item(CustomMenuItem::new( - "game".to_owned(), - t!("backend.tray.no_game_selected"), - )) - .add_submenu(SystemTraySubmenu::new( - t!("backend.tray.auto_backup_interval"), - SystemTrayMenu::new() - .add_item(CustomMenuItem::new( - "timer.0".to_owned(), - t!("backend.tray.turn_off_auto_backup"), - )) - .add_item(CustomMenuItem::new( - "timer.5".to_owned(), - t!("backend.tray.5_minute"), - )) - .add_item(CustomMenuItem::new( - "timer.10".to_owned(), - t!("backend.tray.10_minute"), - )) - .add_item(CustomMenuItem::new( - "timer.30".to_owned(), - t!("backend.tray.30_minute"), - )) - .add_item(CustomMenuItem::new( - "timer.60".to_owned(), - t!("backend.tray.60_minute"), - )), - )) - .add_item(CustomMenuItem::new( - "backup".to_owned(), - t!("backend.tray.quick_backup"), - )) - .add_item(CustomMenuItem::new( - "apply".to_owned(), - t!("backend.tray.quick_apply"), - )) - .add_native_item(SystemTrayMenuItem::Separator) - .add_item(CustomMenuItem::new( - "quit".to_owned(), - t!("backend.tray.exit"), - )); - // Menu items end - - SystemTray::new().with_menu(tray_menu) -} - -pub fn tray_event_handler(app: &AppHandle, event: SystemTrayEvent) { - match event { - SystemTrayEvent::LeftClick { .. } => { - info!(target: "rgsm::tray", "Tray left click"); - if let Some(window) = app.get_window("main") { - window.close().expect("Cannot close window"); - } else { - let window = tauri::WindowBuilder::from_config( - app, - WindowConfig { - label: "main".to_string(), - url: tauri::WindowUrl::App("index.html".into()), - file_drop_enabled: false, // 必须这样设置,否则窗体内js接收不到drag & drop事件 - ..Default::default() - }, - ) - .build() - .unwrap(); - - window - .set_size(LogicalSize { - width: 1280.0, - height: 720.0, - }) - .expect("Cannot set size"); - window.show().expect("Cannot show window"); - window.set_focus().expect("Cannot set focus"); - } - } - SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() { - "backup" => { - info!(target:"rgsm::tray", "Tray quick backup clicked"); - let state: State>> = app.state(); - let game = &state.lock().expect("Cannot get state lock").current_game; - match game { - Some(game) => { - info!(target:"rgsm::tray", "Quick backup game: {:#?}", game); - tauri::async_runtime::block_on(async { - game.create_snapshot("Quick Backup").await - }) - .expect("Tauri async runtime error, cannot block_on"); - Notification::new(&app.config().tauri.bundle.identifier) - .title(t!("backend.tray.success")) - .body(format!( - "{:#?} {} {}", - game.name, - t!("backend.tray.quick_backup"), - t!("backend.tray.success") - )) - .show() - .expect("Cannot show notification"); - } - None => { - warn!(target:"rgsm::tray", "No game selected, cannot quick backup"); - Notification::new(&app.config().tauri.bundle.identifier) - .title(t!("backend.tray.error")) - .body(t!("backend.tray.no_game_selected")) - .show() - .expect("Cannot show notification"); - } - } - } - "apply" => { - info!(target:"rgsm::tray", "Tray quick apply clicked."); - let state: State>> = app.state(); - let game = &state.lock().expect("Cannot get state lock").current_game; - match game { - Some(game) => { - info!(target:"rgsm::tray", "Quick apply game: {:#?}", game); - let newest_date = game - .get_game_snapshots_info() - .expect("Cannot get backup list info") - .backups - .last() - .expect("No backup available") - .date - .clone(); - tauri::async_runtime::block_on(async { - game.restore_snapshot(&newest_date, app) - }) - .expect("Tauri async runtime error, cannot block_on"); - Notification::new(&app.config().tauri.bundle.identifier) - .title(t!("backend.tray.success")) - .body(format!( - "{:#?} {} {}", - game.name, - t!("backend.tray.quick_apply"), - t!("backend.tray.success") - )) - .show() - .expect("Cannot show notification"); - } - None => { - warn!(target:"rgsm::tray","No game selected, cannot quick apply."); - Notification::new(&app.config().tauri.bundle.identifier) - .title(t!("backend.tray.error")) - .body(t!("backend.tray.no_game_selected")) - .show() - .expect("Cannot show notification"); - } - } - } - "quit" => { - info!(target:"rgsm::tray","Tray quit clicked."); - app.exit(0); - } - other => { - info!(target:"rgsm::tray","Tray menu item clicked: {other}."); - if other.starts_with("timer.") { - // safe:所有输入来自程序字面量,保证了不会出现非数字的情况 - let duration = match other.split('.').last().unwrap() { - "0" => None, - // safe:所有输入来自程序字面量,保证了不会出现非数字的情况 - other => Some(other.parse::().unwrap()), - }; - let state: State>> = app.state(); - state - .lock() - .expect("Cannot get state lock") - .auto_backup_duration = duration; - } - } - }, - _ => {} - } -} - -pub fn set_current_game(app: &AppHandle, game: Game) { - info!(target:"rgsm::tray","Setting current quick backup game:{}",game.name); - let state: State>> = app.state(); - app.tray_handle() - .get_item("game") - .set_title(&game.name) - .expect("Cannot get tray handle"); - state.lock().expect("Cannot get state lock").current_game = Some(game); -} - -pub fn setup_timer(app: &mut App) -> Result<(), Box> { - info!(target:"rgsm::tray::timer","Setting up tray timer."); - let state: State>> = app.state(); - let state = state.inner().clone(); - tauri::async_runtime::spawn(async move { - let mut counter = 0; - let mut last = None; - loop { - let (duration, game) = { - let state_guard = state.lock().expect("Cannot get state lock"); - ( - state_guard.auto_backup_duration, - state_guard.current_game.clone(), - ) - }; - if last != duration { - // 如果发生改变,重新计数 - counter = 1; - } - - if let Some(duration) = duration { - if counter >= duration { - info!(target:"rgsm::tray::timer", "Auto backup triggered."); - match &game { - Some(game) => { - info!(target:"rgsm::tray::timer", "Backing up game:{}",game.name); - let show_info = get_config() - .expect("Cannot get config") - .settings - .prompt_when_auto_backup; - game.create_snapshot("Auto Backup Info") - .await - .expect("Cannot backup"); - if show_info { - Notification::new("QuickBackup") - .title(t!("backend.tray.success")) - .body(format!("{:#?}自动备份成功", game.name)) - .show() - .expect("Cannot show notification"); - } - } - None => { - warn!(target:"rgsm::tray::timer", "No game selected, skipping auto backup."); - Notification::new("Auto Backup Info") - .title(t!("backend.tray.error")) - .body(t!("backend.tray.no_game_selected")) - .show() - .expect("Cannot show notification"); - } - } - counter = 0; - } - } - last = duration; - std::thread::sleep(Duration::from_secs(60)); - counter += 1; - counter %= u32::MAX; // 防止溢出 - } - }); - info!(target:"rgsm::tray::timer","Tray timer setup complete."); - Ok(()) -} From cbdb54b6aafbeadc3784f6228da3280d8dadb73a Mon Sep 17 00:00:00 2001 From: Sworld <61224072+mcthesw@users.noreply.github.com> Date: Sat, 28 Sep 2024 01:03:20 +0800 Subject: [PATCH 03/11] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DState=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E9=97=AE=E9=A2=98=EF=BC=9BTimer=E8=A7=A6=E5=8F=91?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E9=97=AE=E9=A2=98=EF=BC=9B=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=87=AA=E5=8A=A8=E5=8D=87=E7=BA=A7=E9=97=AE?= =?UTF-8?q?=E9=A2=98=EF=BC=88=E8=BF=99=E4=BA=9B=E9=97=AE=E9=A2=98=E6=98=AF?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=80=A0=E6=88=90=E7=9A=84=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/config/app_config.rs | 1 + src-tauri/src/default_value.rs | 8 +++++++- src-tauri/src/main.rs | 4 ++-- src-tauri/src/quick_actions/timer.rs | 3 ++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src-tauri/src/config/app_config.rs b/src-tauri/src/config/app_config.rs index b76ad32..9c78a4f 100644 --- a/src-tauri/src/config/app_config.rs +++ b/src-tauri/src/config/app_config.rs @@ -18,6 +18,7 @@ pub struct Config { pub settings: Settings, #[serde(default = "default_value::empty_vec")] pub favorites: Vec, + #[serde(default = "default_value::default_quick_action_settings")] pub quick_action: QuickActionsSettings, } diff --git a/src-tauri/src/default_value.rs b/src-tauri/src/default_value.rs index 0de7557..bf84985 100644 --- a/src-tauri/src/default_value.rs +++ b/src-tauri/src/default_value.rs @@ -1,4 +1,7 @@ -use crate::cloud_sync::{Backend, CloudSettings}; +use crate::{ + cloud_sync::{Backend, CloudSettings}, + config::QuickActionsSettings, +}; pub fn default_false() -> bool { false @@ -30,3 +33,6 @@ pub fn empty_vec() -> Vec { pub fn default_none() -> Option { None } +pub fn default_quick_action_settings() -> QuickActionsSettings { + QuickActionsSettings::default() +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 63f10fa..c5099a9 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -39,10 +39,10 @@ fn main() { // Init app let app = tauri::Builder::default() - .manage(Arc::new(Mutex::new( + .manage(Arc::new( // 自动备份间隔,启动时默认为无(不自动备份) quick_actions::AutoBackupDuration::new(0), - ))) + )) .invoke_handler(tauri::generate_handler![ ipc_handler::open_url, ipc_handler::choose_save_file, diff --git a/src-tauri/src/quick_actions/timer.rs b/src-tauri/src/quick_actions/timer.rs index 549e888..83c7a43 100644 --- a/src-tauri/src/quick_actions/timer.rs +++ b/src-tauri/src/quick_actions/timer.rs @@ -25,7 +25,8 @@ pub fn setup_timer(app: &mut App) -> Result<(), Box> { counter = 1; } - if counter >= duration { + // 时间间隔必须大于0,因为0表示禁用 + if duration > 0 && (counter >= duration) { quick_backup(game, QuickActionType::Timer).await; counter = 0; } From ebc43b06aa47ac19dce4c08c8d611459526c3299 Mon Sep 17 00:00:00 2001 From: Sworld <61224072+mcthesw@users.noreply.github.com> Date: Sat, 28 Sep 2024 17:25:49 +0800 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=E7=9A=84=E7=83=AD=E9=94=AE=E6=94=AF=E6=8C=81=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BF=AB=E6=8D=B7=E5=A4=87=E4=BB=BD=E7=9A=84?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E6=9B=B4=E6=96=B0=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 升级了 Tauri 版本至 1.8.0;增加了热键功能,允许用户通过自定义热键触发快速备份和快速应用操作;进行了大范围的重构 --- src-tauri/Cargo.lock | 322 ++++++++---------- src-tauri/Cargo.toml | 5 +- .../src/config/quick_actions_settings.rs | 19 ++ src-tauri/src/config/utils.rs | 2 +- src-tauri/src/ipc_handler.rs | 2 +- src-tauri/src/main.rs | 24 +- src-tauri/src/quick_actions/hotkeys.rs | 35 ++ src-tauri/src/quick_actions/mod.rs | 4 +- src-tauri/src/quick_actions/timer.rs | 5 +- src-tauri/src/quick_actions/tray.rs | 18 +- src-tauri/src/quick_actions/utils.rs | 23 +- src-tauri/tauri.conf.json | 18 +- 12 files changed, 257 insertions(+), 220 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 5083221..4fbeb7c 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -4,19 +4,13 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -99,9 +93,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "arbitrary" @@ -154,9 +148,9 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", @@ -221,7 +215,7 @@ dependencies = [ "futures-lite 2.3.0", "parking", "polling 3.7.3", - "rustix 0.38.36", + "rustix 0.38.37", "slab", "tracing", "windows-sys 0.59.0", @@ -260,15 +254,15 @@ dependencies = [ "cfg-if", "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.38.36", + "rustix 0.38.37", "windows-sys 0.48.0", ] [[package]] name = "async-process" -version = "2.2.4" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a07789659a4d385b79b18b9127fc27e1a59e1e89117c78c5ea3b806f016374" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" dependencies = [ "async-channel", "async-io 2.3.4", @@ -279,9 +273,8 @@ dependencies = [ "cfg-if", "event-listener 5.3.1", "futures-lite 2.3.0", - "rustix 0.38.36", + "rustix 0.38.37", "tracing", - "windows-sys 0.59.0", ] [[package]] @@ -292,7 +285,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -307,7 +300,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 0.38.36", + "rustix 0.38.37", "signal-hook-registry", "slab", "windows-sys 0.59.0", @@ -321,13 +314,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -362,9 +355,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backon" @@ -380,17 +373,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -508,9 +501,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "bzip2" @@ -569,9 +562,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.16" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d013ecb737093c0e86b151a7b837993cf9ec6c502946cfb44bedc392421e0b" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" dependencies = [ "jobserver", "libc", @@ -795,9 +788,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -909,7 +902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -919,7 +912,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -943,7 +936,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -954,7 +947,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -998,7 +991,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1011,7 +1004,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1061,7 +1054,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1102,9 +1095,9 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "embed-resource" -version = "2.4.3" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4edcacde9351c33139a41e3c97eb2334351a81a2791bebb0b243df837128f602" +checksum = "f4e24052d7be71f0efb50c201557f6fe7d237cfd5a64fd5bcd7fd8fe32dbbffa" dependencies = [ "cc", "memchr", @@ -1153,7 +1146,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1227,9 +1220,9 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fdeflate" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +checksum = "d8090f921a24b04994d9929e204f50b498a33ea6ba559ffaa05e04f7ee7fb5ab" dependencies = [ "simd-adler32", ] @@ -1264,12 +1257,12 @@ checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" [[package]] name = "flate2" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -1410,7 +1403,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1587,9 +1580,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "gio" @@ -1674,9 +1667,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ "aho-corasick", "bstr", @@ -1945,9 +1938,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", "futures-channel", @@ -1958,16 +1951,15 @@ dependencies = [ "pin-project-lite", "socket2 0.5.7", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2014,9 +2006,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" dependencies = [ "crossbeam-deque", "globset", @@ -2060,7 +2052,7 @@ dependencies = [ "libflate", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2125,9 +2117,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" [[package]] name = "is-docker" @@ -2298,9 +2290,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libflate" @@ -2420,9 +2412,9 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] name = "mac-notification-sys" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51fca4d74ff9dbaac16a01b924bc3693fa2bba0862c2c633abc73f9a8ea21f64" +checksum = "dce8f34f3717aa37177e723df6c1fc5fb02b2a1087374ea3fe0ea42316dc8f91" dependencies = [ "cc", "dirs-next", @@ -2509,16 +2501,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", - "simd-adler32", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -2526,6 +2508,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -2616,9 +2599,9 @@ dependencies = [ [[package]] name = "notify-rust" -version = "4.11.1" +version = "4.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a1d03b6305ecefdd9c6c60150179bb8d9f0cd4e64bbcad1e41419e7bf5e414" +checksum = "5134a72dc570b178bff81b01e81ab14a6fcc015391ed4b3b14853090658cd3a3" dependencies = [ "log", "mac-notification-sys", @@ -2840,9 +2823,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -2993,7 +2976,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3040,7 +3023,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3068,9 +3051,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plist" @@ -3087,15 +3070,15 @@ dependencies = [ [[package]] name = "png" -version = "0.17.13" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" dependencies = [ "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", - "miniz_oxide 0.7.4", + "miniz_oxide", ] [[package]] @@ -3124,7 +3107,7 @@ dependencies = [ "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.36", + "rustix 0.38.37", "tracing", "windows-sys 0.59.0", ] @@ -3166,7 +3149,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.20", + "toml_edit 0.22.22", ] [[package]] @@ -3373,9 +3356,9 @@ checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" dependencies = [ "bitflags 2.6.0", ] @@ -3573,7 +3556,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.77", + "syn 2.0.79", "walkdir", ] @@ -3615,7 +3598,7 @@ dependencies = [ "serde", "serde_json", "serde_yml", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3689,9 +3672,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.36" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -3702,9 +3685,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" dependencies = [ "once_cell", "ring", @@ -3726,15 +3709,15 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" [[package]] name = "rustls-webpki" -version = "0.102.7" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -3829,22 +3812,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3868,14 +3851,14 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -3919,7 +3902,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3958,7 +3941,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4176,9 +4159,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -4277,14 +4260,14 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "tar" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" dependencies = [ "filetime", "libc", @@ -4299,9 +4282,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "1.7.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e33e3ba00a3b05eb6c57ef135781717d33728b48acf914bb05629e74d897d29" +checksum = "570a20223602ad990a30a048f2fdb957ae3e38de3ca9582e04cc09d01e8ccfad" dependencies = [ "anyhow", "cocoa", @@ -4318,12 +4301,14 @@ dependencies = [ "heck 0.5.0", "http 0.2.12", "ignore", + "log", "nix 0.26.4", "notify-rust", "objc", "once_cell", "open 3.2.0", "percent-encoding", + "plist", "rand 0.8.5", "raw-window-handle", "regex", @@ -4351,9 +4336,9 @@ dependencies = [ [[package]] name = "tauri-build" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fb5a90a64241ddb7217d3210d844149070a911e87e8a107a707a1d4973f164" +checksum = "586f3e677f940c8bb4f70c52eda05dc59b79e61543f1182de83516810bb8e35d" dependencies = [ "anyhow", "cargo_toml", @@ -4411,7 +4396,7 @@ dependencies = [ [[package]] name = "tauri-plugin-single-instance" version = "0.0.0" -source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#5c249a1a1076ac78cfc0ed4c2857cf7e2540b1cc" +source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#0b59bc7096dfc7ff1b141c31457a2a0a4a5f9ad1" dependencies = [ "log", "serde", @@ -4523,7 +4508,7 @@ dependencies = [ "cfg-if", "fastrand 2.1.1", "once_cell", - "rustix 0.38.36", + "rustix 0.38.37", "windows-sys 0.59.0", ] @@ -4546,22 +4531,22 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4700,7 +4685,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.20", + "toml_edit 0.22.22", ] [[package]] @@ -4727,38 +4712,17 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap 2.5.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow 0.6.20", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - [[package]] name = "tower-service" version = "0.3.3" @@ -4796,7 +4760,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4887,24 +4851,24 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "untrusted" @@ -5043,7 +5007,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-shared", ] @@ -5077,7 +5041,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5090,9 +5054,9 @@ checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" dependencies = [ "futures-util", "js-sys", @@ -5160,9 +5124,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.5" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -5331,7 +5295,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5342,7 +5306,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5681,9 +5645,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -5765,7 +5729,7 @@ checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", "linux-raw-sys 0.4.14", - "rustix 0.38.36", + "rustix 0.38.37", ] [[package]] @@ -5830,7 +5794,7 @@ dependencies = [ "async-fs 2.1.2", "async-io 2.3.4", "async-lock 3.4.0", - "async-process 2.2.4", + "async-process 2.3.0", "async-recursion", "async-task", "async-trait", @@ -5880,7 +5844,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "zvariant_utils 2.1.0", ] @@ -5924,7 +5888,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -5944,7 +5908,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -6067,7 +6031,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "zvariant_utils 2.1.0", ] @@ -6090,5 +6054,5 @@ checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 1581513..db2469e 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -16,12 +16,11 @@ tauri-build = { version = "1.5.2", features = [] } serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } tauri = { version = "1.6.8", features = [ - "notification-all", "shell-open", "dialog", "system-tray", - "notification", - "global-shortcut", + "notification-all", + "global-shortcut-all", ] } anyhow = "1.0.69" chrono = "0.4.23" diff --git a/src-tauri/src/config/quick_actions_settings.rs b/src-tauri/src/config/quick_actions_settings.rs index b07256a..bcbc753 100644 --- a/src-tauri/src/config/quick_actions_settings.rs +++ b/src-tauri/src/config/quick_actions_settings.rs @@ -15,3 +15,22 @@ pub struct QuickActionsSettings { #[serde(default = "default_value::empty_vec")] pub hotkeys: Vec<(String, QuickActions)>, } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn quick_actions_settings_serialize() { + let settings = QuickActionsSettings { + quick_action_game: Some(Game { + name: "test1".to_string(), + save_paths: vec![], + game_path: None, + }), + hotkeys: vec![("CmdOrCtrl+Space".to_string(), QuickActions::Backup)], + }; + let serialized = serde_json::to_string_pretty(&settings).unwrap(); + println!("{}", serialized); + } +} diff --git a/src-tauri/src/config/utils.rs b/src-tauri/src/config/utils.rs index ddfc8d3..fb63b0f 100644 --- a/src-tauri/src/config/utils.rs +++ b/src-tauri/src/config/utils.rs @@ -91,7 +91,7 @@ fn upgrade_config_version( ) -> Result<(), ConfigError> { // 由于1.0之后版本保持了兼容性,因此不需要做任何处理,仅更新版本号并保存 config.version = software_version.to_string(); - tauri::async_runtime::block_on(async { set_config(config).await })?; + tauri::async_runtime::block_on(set_config(config))?; Ok(()) } diff --git a/src-tauri/src/ipc_handler.rs b/src-tauri/src/ipc_handler.rs index 67d2916..8ee42ef 100644 --- a/src-tauri/src/ipc_handler.rs +++ b/src-tauri/src/ipc_handler.rs @@ -297,7 +297,7 @@ pub async fn apply_all(app_handle: AppHandle) -> Result<(), String> { #[tauri::command] pub async fn set_quick_backup_game(app_handle: AppHandle, game: Game) -> Result<(), String> { info!(target:"rgsm::ipc","Setting quick backup game to: {:?}", game); - quick_actions::set_current_game(&app_handle, game); + quick_actions::set_current_game(&app_handle, game).await; Ok(()) } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index c5099a9..8a68c9c 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -10,7 +10,7 @@ i18n!("../locales", fallback = ["en_US", "zh_SIMPLIFIED"]); use config::{get_config, Config}; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use tauri::api::notification::Notification; use tracing::info; use tracing_subscriber::{filter::LevelFilter, Layer}; @@ -70,25 +70,27 @@ fn main() { // 只允许运行一个实例 let app = app.plugin(tauri_plugin_single_instance::init(|_app, _argv, _cwd| {})); - // 处理退出到托盘 + // 处理快捷备份和托盘的事件 + let app = app + .system_tray(quick_actions::get_tray()) + .on_system_tray_event(quick_actions::tray_event_handler) + .setup(quick_actions::setup); + + // 处理退出到托盘(关闭窗口不退出) if config.settings.exit_to_tray { - app.system_tray(quick_actions::get_tray()) - .on_system_tray_event(quick_actions::tray_event_handler) - .setup(quick_actions::setup_timer) - .build(tauri::generate_context!()) + app.build(tauri::generate_context!()) .expect("Cannot build tauri app") .run(|_app_handle, event| { if let tauri::RunEvent::ExitRequested { api, .. } = event { api.prevent_exit(); } }); - return; + } else { + // 不需要退出到托盘 + app.run(tauri::generate_context!()) + .expect("error while running tauri application"); } - // 不需要退出到托盘 - app.run(tauri::generate_context!()) - .expect("error while running tauri application"); - // 需要初始化Notification,否则第一次提示不会显示 Notification::new("Init Info") .title("Init") diff --git a/src-tauri/src/quick_actions/hotkeys.rs b/src-tauri/src/quick_actions/hotkeys.rs index e69de29..51ffc8f 100644 --- a/src-tauri/src/quick_actions/hotkeys.rs +++ b/src-tauri/src/quick_actions/hotkeys.rs @@ -0,0 +1,35 @@ +use tauri::App; +use tauri::GlobalShortcutManager; + +use super::*; +use crate::config::Config; +use crate::config::QuickActions; + +pub fn setup_hotkeys(config: &Config, app: &mut App) -> Result<(), Box> { + let mut manager = app.global_shortcut_manager(); + config + .quick_action + .hotkeys + .iter() + .for_each(|(hotkey, action)| { + manager + .register(hotkey, action_to_function(action)) + .expect("Cannot setup hotkeys"); + }); + Ok(()) +} + +fn action_to_function(action: &QuickActions) -> impl Fn() { + match action { + QuickActions::Apply => move || { + tauri::async_runtime::spawn(async move { + quick_apply(QuickActionType::Hotkey).await; + }); + }, + QuickActions::Backup => move || { + tauri::async_runtime::spawn(async move { + quick_backup(QuickActionType::Hotkey).await; + }); + }, + } +} diff --git a/src-tauri/src/quick_actions/mod.rs b/src-tauri/src/quick_actions/mod.rs index 8cf0375..8c81e57 100644 --- a/src-tauri/src/quick_actions/mod.rs +++ b/src-tauri/src/quick_actions/mod.rs @@ -5,6 +5,6 @@ mod utils; use utils::*; -pub use timer::{setup_timer, AutoBackupDuration}; +pub use timer::AutoBackupDuration; pub use tray::{get_tray, tray_event_handler}; -pub use utils::set_current_game; +pub use utils::{set_current_game, setup}; diff --git a/src-tauri/src/quick_actions/timer.rs b/src-tauri/src/quick_actions/timer.rs index 83c7a43..b77d6ca 100644 --- a/src-tauri/src/quick_actions/timer.rs +++ b/src-tauri/src/quick_actions/timer.rs @@ -6,7 +6,7 @@ use std::{ use tauri::{App, Manager, State}; use tracing::info; -use super::{get_quick_action_game, quick_backup, QuickActionType}; +use super::{quick_backup, QuickActionType}; pub type AutoBackupDuration = AtomicU32; @@ -19,7 +19,6 @@ pub fn setup_timer(app: &mut App) -> Result<(), Box> { let mut last = 0; loop { let duration = state.load(std::sync::atomic::Ordering::Relaxed); - let game = get_quick_action_game(); if last != duration { // 如果发生改变,重新计数 counter = 1; @@ -27,7 +26,7 @@ pub fn setup_timer(app: &mut App) -> Result<(), Box> { // 时间间隔必须大于0,因为0表示禁用 if duration > 0 && (counter >= duration) { - quick_backup(game, QuickActionType::Timer).await; + quick_backup(QuickActionType::Timer).await; counter = 0; } diff --git a/src-tauri/src/quick_actions/tray.rs b/src-tauri/src/quick_actions/tray.rs index 3eee669..7559def 100644 --- a/src-tauri/src/quick_actions/tray.rs +++ b/src-tauri/src/quick_actions/tray.rs @@ -1,14 +1,11 @@ use std::sync::Arc; use tauri::{ - utils::config::WindowConfig, AppHandle, CustomMenuItem, - LogicalSize, Manager, State, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, - SystemTraySubmenu, + utils::config::WindowConfig, AppHandle, CustomMenuItem, LogicalSize, Manager, State, + SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem, SystemTraySubmenu, }; use tracing::info; -use crate::quick_actions::get_quick_action_game; - use super::{quick_apply, quick_backup, AutoBackupDuration, QuickActionType}; use rust_i18n::t; @@ -76,6 +73,7 @@ pub fn tray_event_handler(app: &AppHandle, event: SystemTrayEvent) { label: "main".to_string(), url: tauri::WindowUrl::App("index.html".into()), file_drop_enabled: false, // 必须这样设置,否则窗体内js接收不到drag & drop事件 + title: "RustyManager".to_string(), ..Default::default() }, ) @@ -95,16 +93,14 @@ pub fn tray_event_handler(app: &AppHandle, event: SystemTrayEvent) { SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() { "backup" => { info!(target:"rgsm::quick_action::tray", "Tray quick backup clicked"); - let game = get_quick_action_game(); - tauri::async_runtime::block_on(async { - quick_backup(game, QuickActionType::Tray).await + tauri::async_runtime::spawn(async move { + quick_backup(QuickActionType::Tray).await; }); } "apply" => { info!(target:"rgsm::quick_action::tray", "Tray quick apply clicked."); - let game = get_quick_action_game(); - tauri::async_runtime::block_on(async { - quick_apply(game, QuickActionType::Tray).await + tauri::async_runtime::spawn(async move { + quick_apply(QuickActionType::Tray).await; }); } "quit" => { diff --git a/src-tauri/src/quick_actions/utils.rs b/src-tauri/src/quick_actions/utils.rs index 7ffa125..d02ef7e 100644 --- a/src-tauri/src/quick_actions/utils.rs +++ b/src-tauri/src/quick_actions/utils.rs @@ -6,7 +6,9 @@ use crate::{ config::{get_config, set_config}, }; -pub fn set_current_game(app: &AppHandle, game: Game) { +use super::*; + +pub async fn set_current_game(app: &AppHandle, game: Game) { info!(target:"rgsm::tray","Setting current quick backup game:{}",game.name); app.tray_handle() .get_item("game") @@ -14,7 +16,7 @@ pub fn set_current_game(app: &AppHandle, game: Game) { .expect("Cannot get tray handle"); let mut config = get_config().expect("Cannot get config"); config.quick_action.quick_action_game = Some(game); - tauri::async_runtime::block_on(async { set_config(&config).await }).expect("Cannot set config"); + set_config(&config).await.expect("Cannot set config"); } #[derive(Debug, PartialEq)] @@ -34,8 +36,9 @@ impl QuickActionType { } } -pub async fn quick_apply(game: Option, t: QuickActionType) { +pub async fn quick_apply(t: QuickActionType) { info!(target:"rgsm::quick_action", "Auto apply triggered: {:#?}",t.generate_describe()); + let game = get_quick_action_game(); match game { Some(game) => { info!(target:"rgsm::quick_action", "Quick apply game: {:#?}", game); @@ -47,8 +50,8 @@ pub async fn quick_apply(game: Option, t: QuickActionType) { .expect("No backup available") .date .clone(); - tauri::async_runtime::block_on(async { game.restore_snapshot(&newest_date, None) }) - .expect("Cannot restore save"); + game.restore_snapshot(&newest_date, None) + .expect("Cannot apply"); Notification::new("QuickAction") .title(t!("backend.tray.success")) .body(format!( @@ -64,8 +67,9 @@ pub async fn quick_apply(game: Option, t: QuickActionType) { } } -pub async fn quick_backup(game: Option, t: QuickActionType) { +pub async fn quick_backup(t: QuickActionType) { info!(target:"rgsm::quick_action", "Auto backup triggered: {:#?}",t.generate_describe()); + let game = get_quick_action_game(); // TODO:这里可以让match有返回值来判断是否出错 match &game { None => show_no_game_selected_error(), @@ -112,3 +116,10 @@ pub fn get_quick_action_game() -> Option { .quick_action_game .clone() } + +pub fn setup(app: &mut tauri::App) -> Result<(), Box> { + let config = get_config()?; + timer::setup_timer(app)?; + hotkeys::setup_hotkeys(&config, app)?; + Ok(()) +} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 38ddd9a..a623463 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -23,6 +23,9 @@ }, "notification": { "all": true + }, + "globalShortcut": { + "all": true } }, "bundle": { @@ -50,12 +53,21 @@ "signingIdentity": null }, "shortDescription": "", - "targets": ["appimage", "deb", "nsis", "dmg"], + "targets": [ + "appimage", + "deb", + "nsis", + "dmg" + ], "windows": { "digestAlgorithm": "sha256", "timestampUrl": "", "nsis": { - "languages": ["English", "SimpChinese", "TradChinese"], + "languages": [ + "English", + "SimpChinese", + "TradChinese" + ], "installMode": "both" } } @@ -77,4 +89,4 @@ } ] } -} +} \ No newline at end of file From 29394f12beef67c1f3b3e2782d94b9a6df1f0c77 Mon Sep 17 00:00:00 2001 From: Sworld <61224072+mcthesw@users.noreply.github.com> Date: Sat, 28 Sep 2024 19:08:16 +0800 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E5=BF=AB?= =?UTF-8?q?=E9=80=9F=E6=93=8D=E4=BD=9C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增强快速备份/恢复功能的错误处理,并在错误发生时显示详细的错误信息。 优化代码结构,提高可读性和可维护性。 --- locales/en_US.json | 5 +- locales/zh_SIMPLIFIED.json | 3 +- src-tauri/src/errors.rs | 1 + src-tauri/src/quick_actions/utils.rs | 119 +++++++++++++++++---------- 4 files changed, 81 insertions(+), 47 deletions(-) diff --git a/locales/en_US.json b/locales/en_US.json index 0229a7f..861d782 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -258,7 +258,8 @@ "quick_apply": "Quick apply", "exit": "Exit", "success": "Success", - "error": "Error" + "error": "Error", + "find_error_detail": "Please check the log file for details" }, "backup": { "extra_backup_file_not_exist": "Since the file does not exist, the extra backup (pre-overwrite backup) cannot be completed and the recovery is aborted. If you don't need this feature, turn it off in settings.", @@ -286,4 +287,4 @@ "enable_edit": "Enable editing: You can drag and drop items directly to sort them", "game_not_found": "It is recommended to delete this collection as the game does not exist:" } -} \ No newline at end of file +} diff --git a/locales/zh_SIMPLIFIED.json b/locales/zh_SIMPLIFIED.json index 2095d58..dd2f74e 100644 --- a/locales/zh_SIMPLIFIED.json +++ b/locales/zh_SIMPLIFIED.json @@ -258,7 +258,8 @@ "quick_apply": "快速读档", "exit": "退出", "success": "成功", - "error": "错误" + "error": "错误", + "find_error_detail": "请在日志文件中查看详情" }, "backup": { "extra_backup_file_not_exist": "由于文件不存在,无法完成额外备份(覆盖前备份),恢复中止。如果不需要该功能,请在设置中关闭。", diff --git a/src-tauri/src/errors.rs b/src-tauri/src/errors.rs index 5223f8d..eb40d17 100644 --- a/src-tauri/src/errors.rs +++ b/src-tauri/src/errors.rs @@ -62,6 +62,7 @@ impl From for BackendError { } } +/// 备份或恢复快照时可能产生的错误 #[derive(Debug, Error)] pub enum BackupError { #[error("Backup for {name} not exists: {date}")] diff --git a/src-tauri/src/quick_actions/utils.rs b/src-tauri/src/quick_actions/utils.rs index d02ef7e..9889b11 100644 --- a/src-tauri/src/quick_actions/utils.rs +++ b/src-tauri/src/quick_actions/utils.rs @@ -1,9 +1,10 @@ use tauri::{api::notification::Notification, AppHandle}; -use tracing::{info, warn}; +use tracing::{error, info, warn}; use crate::{ backup::Game, config::{get_config, set_config}, + errors::BackupError, }; use super::*; @@ -39,76 +40,106 @@ impl QuickActionType { pub async fn quick_apply(t: QuickActionType) { info!(target:"rgsm::quick_action", "Auto apply triggered: {:#?}",t.generate_describe()); let game = get_quick_action_game(); - match game { - Some(game) => { - info!(target:"rgsm::quick_action", "Quick apply game: {:#?}", game); - let newest_date = game - .get_game_snapshots_info() - .expect("Cannot get backup list info") - .backups - .last() - .expect("No backup available") - .date - .clone(); - game.restore_snapshot(&newest_date, None) - .expect("Cannot apply"); - Notification::new("QuickAction") - .title(t!("backend.tray.success")) - .body(format!( + // 这里使用立即执行的闭包是为了做错误处理 + let result: Result<(), BackupError> = (|| { + match &game { + Some(game) => { + info!(target:"rgsm::quick_action", "Quick apply game: {:#?}", game); + let newest_date = game + .get_game_snapshots_info()? + .backups + .last() + .ok_or(BackupError::NoBackupAvailable)? + .date + .clone(); + game.restore_snapshot(&newest_date, None)?; + } + None => show_no_game_selected_error(), + }; + Ok(()) + })(); + match result { + Err(e) => { + error!(target:"rgsm::quick_action", "Quick apply failed: {:#?}", &e); + show_notification( + t!("backend.tray.error"), + format!("{:#?}\n{:#?}", t!("backend.tray.find_error_detail"), e), + ); + } + Ok(_) => { + show_notification( + t!("backend.tray.success"), + format!( "{:#?} {} {}", - game.name, + game.unwrap().name, // safe:因为前面已经判断了game是否为None t!("backend.tray.quick_apply"), t!("backend.tray.success") - )) - .show() - .expect("Cannot show notification"); + ), + ); } - None => show_no_game_selected_error(), } } pub async fn quick_backup(t: QuickActionType) { info!(target:"rgsm::quick_action", "Auto backup triggered: {:#?}",t.generate_describe()); let game = get_quick_action_game(); - // TODO:这里可以让match有返回值来判断是否出错 - match &game { - None => show_no_game_selected_error(), - Some(game) => { - let show_info = get_config() - .expect("Cannot get config") - .settings - .prompt_when_auto_backup; - game.create_snapshot(&t.generate_describe()) - .await - .expect("Cannot backup"); + let show_info = get_config() + .expect("Cannot get config") + .settings + .prompt_when_auto_backup; + let result: Result<(), BackupError> = async { + match &game { + None => show_no_game_selected_error(), + Some(game) => { + game.create_snapshot(&t.generate_describe()).await?; + } + }; + Ok(()) + } + .await; + match result { + Err(e) => { + error!(target:"rgsm::quick_action", "Quick backup failed: {:#?}", &e); + show_notification( + t!("backend.tray.error"), + format!("{:#?}\n{:#?}", t!("backend.tray.find_error_detail"), e), + ); + } + Ok(_) => { if !show_info && (t == QuickActionType::Timer) { // 设置中该选项控制是否在按间隔备份时发出通知 // 若不启用,则不进行通知,其余情况则产生通知 return; } - Notification::new("QuickAction") - .title(t!("backend.tray.success")) - .body(format!( + show_notification( + t!("backend.tray.success"), + format!( "{:#?} {} {}", - game.name, + game.unwrap().name, // safe:因为前面已经判断了game是否为None t!("backend.tray.quick_backup"), t!("backend.tray.success") - )) - .show() - .expect("Cannot show notification"); + ), + ); } } } -fn show_no_game_selected_error() { - warn!(target:"rgsm::quick_action", "No game selected, cannot quick backup/apply"); +fn show_notification, T2: Into>(title: T1, body: T2) { Notification::new("QuickAction") - .title(t!("backend.tray.error")) - .body(t!("backend.tray.no_game_selected")) + .title(title) + .body(body) .show() .expect("Cannot show notification"); } +fn show_no_game_selected_error() { + warn!(target:"rgsm::quick_action", "No game selected, cannot quick backup/apply"); + show_notification( + t!("backend.tray.error"), + t!("backend.tray.no_game_selected"), + ); +} + pub fn get_quick_action_game() -> Option { get_config() .expect("Cannot get config") From c86ffa2d92cf88056cc94b57a0fcfcc4a2bcbd55 Mon Sep 17 00:00:00 2001 From: Sworld <61224072+mcthesw@users.noreply.github.com> Date: Sat, 28 Sep 2024 23:34:11 +0800 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E7=83=AD?= =?UTF-8?q?=E9=94=AE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 `QuickActions` 枚举类型替换为 `QuickActionHotkeys` 结构体,支持更灵活的热键配置。 - 修改 `default_value` 模块中的默认值生成函数,使用泛型默认值生成器。 - 更新 `hotkeys.rs` 中的热键注册逻辑,支持多热键组合。 - 更新多语言文件,添加快捷操作热键设置的相关翻译。 - 更新 `Settings.vue` 视图,添加热键选择器组件。 #140 --- locales/en_US.json | 11 +- locales/zh_SIMPLIFIED.json | 11 +- package.json | 2 + pnpm-lock.yaml | 6 + src-tauri/src/config/app_config.rs | 2 +- src-tauri/src/config/mod.rs | 2 +- .../src/config/quick_actions_settings.rs | 14 +-- src-tauri/src/config/settings.rs | 2 +- src-tauri/src/default_value.rs | 12 +- src-tauri/src/quick_actions/hotkeys.rs | 49 ++++---- src/components/HotkeySelector.vue | 62 +++++++++ src/components/MainSideBar.vue | 5 +- src/schemas/hotkeyMap.ts | 119 ++++++++++++++++++ src/schemas/saveTypes.ts | 23 ++++ src/views/Settings.vue | 13 ++ 15 files changed, 285 insertions(+), 48 deletions(-) create mode 100644 src/components/HotkeySelector.vue create mode 100644 src/schemas/hotkeyMap.ts diff --git a/locales/en_US.json b/locales/en_US.json index 861d782..45e218e 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -37,7 +37,13 @@ "open_log_folder": "Open log", "log_to_file": "Generate file log", "setting_tips": "An asterisk indicates that it will take effect after restarting, and the remaining settings will take effect after saving.", - "add_new_to_favorites": "New games are automatically added to favorites" + "add_new_to_favorites": "New games are automatically added to favorites", + "quick_action_hotkeys": "Quick backup/restore hotkey settings (settings need to be saved)", + "hotkey": { + "quick_backup": "Quick backup", + "hint": "Note that the settings here are the same as other settings with an asterisk. They need to be saved and restarted to take effect. Setting it to empty will disable this function.", + "quick_apply": "Quick file reading" + } }, "home": { "hello_world": "Hello world", @@ -286,5 +292,8 @@ "add_success": "Node added successfully", "enable_edit": "Enable editing: You can drag and drop items directly to sort them", "game_not_found": "It is recommended to delete this collection as the game does not exist:" + }, + "setting": { + "current_quick_action_game": "Current quick backup games" } } diff --git a/locales/zh_SIMPLIFIED.json b/locales/zh_SIMPLIFIED.json index dd2f74e..401a0c6 100644 --- a/locales/zh_SIMPLIFIED.json +++ b/locales/zh_SIMPLIFIED.json @@ -37,7 +37,13 @@ "open_log_folder": "打开日志", "log_to_file": "生成文件日志", "setting_tips": "带有星号表示重启后生效,其余设置保存后生效", - "add_new_to_favorites": "新游戏自动加入收藏夹" + "add_new_to_favorites": "新游戏自动加入收藏夹", + "quick_action_hotkeys": "快捷备份/恢复热键设置(需要保存设置)", + "hotkey": { + "hint": "注意,此处设置和其他带有星号设置一样,需要保存并且重启生效,设置为全空即禁用该功能", + "quick_backup": "快速备份", + "quick_apply": "快速读档" + } }, "home": { "hello_world": "你好 世界", @@ -286,5 +292,8 @@ "add_success": "成功添加节点", "game_not_found": "建议删除该收藏,因为游戏不存在:", "enable_edit": "启用编辑:可以直接拖拽项目进行排序" + }, + "setting": { + "current_quick_action_game": "当前快捷备份的游戏" } } \ No newline at end of file diff --git a/package.json b/package.json index 96a6a52..73d2d87 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,10 @@ "dependencies": { "@element-plus/icons-vue": "^2.3.1", "@tauri-apps/api": "^1.5.6", + "@types/lodash": "^4.17.9", "@vueuse/core": "^10.10.0", "element-plus": "^2.7.4", + "lodash": "^4.17.21", "pinia": "^2.1.7", "uuid": "^9.0.1", "vue": "^3.4.27", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 069b4c1..71a8f46 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,12 +11,18 @@ dependencies: '@tauri-apps/api': specifier: ^1.5.6 version: 1.6.0 + '@types/lodash': + specifier: ^4.17.9 + version: 4.17.9 '@vueuse/core': specifier: ^10.10.0 version: 10.11.1(vue@3.5.9) element-plus: specifier: ^2.7.4 version: 2.8.3(vue@3.5.9) + lodash: + specifier: ^4.17.21 + version: 4.17.21 pinia: specifier: ^2.1.7 version: 2.2.2(typescript@5.6.2)(vue@3.5.9) diff --git a/src-tauri/src/config/app_config.rs b/src-tauri/src/config/app_config.rs index 9c78a4f..892c12e 100644 --- a/src-tauri/src/config/app_config.rs +++ b/src-tauri/src/config/app_config.rs @@ -18,7 +18,7 @@ pub struct Config { pub settings: Settings, #[serde(default = "default_value::empty_vec")] pub favorites: Vec, - #[serde(default = "default_value::default_quick_action_settings")] + #[serde(default = "default_value::default")] pub quick_action: QuickActionsSettings, } diff --git a/src-tauri/src/config/mod.rs b/src-tauri/src/config/mod.rs index 63abd11..2f5a093 100644 --- a/src-tauri/src/config/mod.rs +++ b/src-tauri/src/config/mod.rs @@ -4,6 +4,6 @@ mod settings; mod utils; pub use app_config::Config; -pub use quick_actions_settings::{QuickActions, QuickActionsSettings}; +pub use quick_actions_settings::QuickActionsSettings; pub use settings::Settings; pub use utils::*; diff --git a/src-tauri/src/config/quick_actions_settings.rs b/src-tauri/src/config/quick_actions_settings.rs index bcbc753..9b81674 100644 --- a/src-tauri/src/config/quick_actions_settings.rs +++ b/src-tauri/src/config/quick_actions_settings.rs @@ -2,18 +2,18 @@ use serde::{Deserialize, Serialize}; use crate::{backup::Game, default_value}; -#[derive(Debug, Serialize, Deserialize, Clone)] -pub enum QuickActions { - Apply, - Backup, +#[derive(Debug, Serialize, Deserialize, Clone, Default)] +pub struct QuickActionHotkeys { + pub apply: Vec, + pub backup: Vec, } #[derive(Debug, Serialize, Deserialize, Clone, Default)] pub struct QuickActionsSettings { #[serde(default = "default_value::default_none")] pub quick_action_game: Option, - #[serde(default = "default_value::empty_vec")] - pub hotkeys: Vec<(String, QuickActions)>, + #[serde(default = "default_value::default")] + pub hotkeys: QuickActionHotkeys, } #[cfg(test)] @@ -28,7 +28,7 @@ mod test { save_paths: vec![], game_path: None, }), - hotkeys: vec![("CmdOrCtrl+Space".to_string(), QuickActions::Backup)], + hotkeys: QuickActionHotkeys::default(), }; let serialized = serde_json::to_string_pretty(&settings).unwrap(); println!("{}", serialized); diff --git a/src-tauri/src/config/settings.rs b/src-tauri/src/config/settings.rs index 32cf31e..314cb29 100644 --- a/src-tauri/src/config/settings.rs +++ b/src-tauri/src/config/settings.rs @@ -17,7 +17,7 @@ pub struct Settings { pub prompt_when_auto_backup: bool, #[serde(default = "default_value::default_true")] pub exit_to_tray: bool, - #[serde(default = "default_value::default_cloud_settings")] + #[serde(default = "default_value::default")] pub cloud_settings: CloudSettings, #[serde(default = "default_value::default_locale")] pub locale: String, diff --git a/src-tauri/src/default_value.rs b/src-tauri/src/default_value.rs index bf84985..7e227b9 100644 --- a/src-tauri/src/default_value.rs +++ b/src-tauri/src/default_value.rs @@ -1,7 +1,4 @@ -use crate::{ - cloud_sync::{Backend, CloudSettings}, - config::QuickActionsSettings, -}; +use crate::cloud_sync::Backend; pub fn default_false() -> bool { false @@ -21,9 +18,6 @@ pub fn default_home_page() -> String { pub fn default_backend() -> Backend { Backend::Disabled } -pub fn default_cloud_settings() -> CloudSettings { - CloudSettings::default() -} pub fn default_locale() -> String { "zh_SIMPLIFIED".to_owned() } @@ -33,6 +27,6 @@ pub fn empty_vec() -> Vec { pub fn default_none() -> Option { None } -pub fn default_quick_action_settings() -> QuickActionsSettings { - QuickActionsSettings::default() +pub fn default() -> T { + T::default() } diff --git a/src-tauri/src/quick_actions/hotkeys.rs b/src-tauri/src/quick_actions/hotkeys.rs index 51ffc8f..aff8f37 100644 --- a/src-tauri/src/quick_actions/hotkeys.rs +++ b/src-tauri/src/quick_actions/hotkeys.rs @@ -3,33 +3,34 @@ use tauri::GlobalShortcutManager; use super::*; use crate::config::Config; -use crate::config::QuickActions; pub fn setup_hotkeys(config: &Config, app: &mut App) -> Result<(), Box> { let mut manager = app.global_shortcut_manager(); - config - .quick_action - .hotkeys - .iter() - .for_each(|(hotkey, action)| { - manager - .register(hotkey, action_to_function(action)) - .expect("Cannot setup hotkeys"); - }); - Ok(()) -} -fn action_to_function(action: &QuickActions) -> impl Fn() { - match action { - QuickActions::Apply => move || { - tauri::async_runtime::spawn(async move { - quick_apply(QuickActionType::Hotkey).await; - }); - }, - QuickActions::Backup => move || { - tauri::async_runtime::spawn(async move { - quick_backup(QuickActionType::Hotkey).await; - }); - }, + let mut apply_keys = config.quick_action.hotkeys.apply.clone(); + apply_keys.retain(|x| !x.is_empty()); + if !config.quick_action.hotkeys.apply.is_empty() { + let key_string = apply_keys.join("+"); + manager + .register(&key_string, move || { + tauri::async_runtime::spawn(async move { + quick_apply(QuickActionType::Hotkey).await; + }); + }) + .expect("Cannot setup hotkeys"); } + + let mut backup_keys = config.quick_action.hotkeys.backup.clone(); + backup_keys.retain(|x| !x.is_empty()); + if !config.quick_action.hotkeys.backup.is_empty() { + let key_string = backup_keys.join("+"); + manager + .register(&key_string, move || { + tauri::async_runtime::spawn(async move { + quick_backup(QuickActionType::Hotkey).await; + }); + }) + .expect("Cannot setup hotkeys"); + } + Ok(()) } diff --git a/src/components/HotkeySelector.vue b/src/components/HotkeySelector.vue new file mode 100644 index 0000000..ebe70cf --- /dev/null +++ b/src/components/HotkeySelector.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/src/components/MainSideBar.vue b/src/components/MainSideBar.vue index adbbf54..a45daa1 100644 --- a/src/components/MainSideBar.vue +++ b/src/components/MainSideBar.vue @@ -7,13 +7,12 @@ import { InfoFilled, HotWater, Setting, - MostlyCloudy, Grid + MostlyCloudy } from "@element-plus/icons-vue"; import { useRoute, useRouter } from "vue-router"; import { useConfig } from "../stores/ConfigFile"; import { $t } from "../i18n"; -import { ElContainer, ElIcon, ElRow, ElScrollbar, ElTree } from "element-plus"; -import { FavoriteTreeNode } from "../schemas/saveTypes"; +import { ElContainer, ElIcon, ElRow, ElScrollbar } from "element-plus"; let config = useConfig(); diff --git a/src/schemas/hotkeyMap.ts b/src/schemas/hotkeyMap.ts new file mode 100644 index 0000000..d388ce8 --- /dev/null +++ b/src/schemas/hotkeyMap.ts @@ -0,0 +1,119 @@ +// NOTICE: 以下代码来自 https://github.com/tauri-apps/tauri/discussions/7121 +// 这些代码是通过该文件获得的: https://github.com/tauri-apps/global-hotkey/blob/c9913a97667b3e44cb000de384cd8937d5a0050a/src/hotkey.rs#L212 +// 上述链接目标遵循 Apache-2.0/MIT 协议,本项目根据MIT协议合理使用该代码 +// 授权协议文件请参考 https://github.com/tauri-apps/global-hotkey/blob/dev/LICENSE-MIT + + +// src/schemas/hotkeyMap.ts (7-114) +export const otherKeys = [ + 'COMMA', + 'EQUAL', + 'MINUS', + 'PERIOD', + 'QUOTE', + 'SEMICOLON', + 'SLASH', + 'BACKSPACE', + 'ENTER', + 'SPACE', + 'TAB', + 'DELETE', + 'END', + 'HOME', + 'INSERT', + 'PAGEDOWN', + 'PAGEUP', + 'ARROWDOWN', + 'ARROWLEFT', + 'ARROWRIGHT', + 'ARROWUP', + 'NUMPADADD', + 'NUMPADDECIMAL', + 'NUMPADDIVIDE', + 'NUMPADENTER', + 'NUMPADEQUAL', + 'NUMPADMULTIPLY', + 'NUMPADSUBTRACT' +]; + +export const funcKeys1 = [ + '', + 'SHIFT', + 'CONTROL', + 'ALT', + 'SUPER', +]; + +export const funcKeys2 = [ + '', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + 'NUMPAD0', + 'NUMPAD1', + 'NUMPAD2', + 'NUMPAD3', + 'NUMPAD4', + 'NUMPAD5', + 'NUMPAD6', + 'NUMPAD7', + 'NUMPAD8', + 'NUMPAD9', + 'F1', + 'F2', + 'F3', + 'F4', + 'F5', + 'F6', + 'F7', + 'F8', + 'F9', + 'F10', + 'F11', + 'F12', + 'F13', + 'F14', + 'F15', + 'F16', + 'F17', + 'F18', + 'F19', + 'F20', + 'F21', + 'F22', + 'F23', + 'F24' +] diff --git a/src/schemas/saveTypes.ts b/src/schemas/saveTypes.ts index a38bc3c..0a2d914 100644 --- a/src/schemas/saveTypes.ts +++ b/src/schemas/saveTypes.ts @@ -131,6 +131,19 @@ export interface FavoriteTreeNode { children?: FavoriteTreeNode[]; } +export interface QuickActionsSettings { + /** + * 当前启用快捷备份的游戏 + */ + quick_action_game?: Game; + /** + * 快捷键与其对应的操作列表 + */ + hotkeys: { + backup: string[], + apply: string[] + }; +} export interface Config { /** @@ -153,6 +166,10 @@ export interface Config { * 收藏夹 */ favorites: Array; + /** + * 快捷备份设置,包含当前游戏和快捷键绑定的指令 + */ + quick_action: QuickActionsSettings; } export let default_config: Config = { @@ -181,6 +198,12 @@ export let default_config: Config = { add_new_to_favorites: false }, favorites: [], + quick_action: { + hotkeys: { + backup: [], + apply: [] + } + } }; export { Backend }; diff --git a/src/views/Settings.vue b/src/views/Settings.vue index c5d2c28..9bca6da 100644 --- a/src/views/Settings.vue +++ b/src/views/Settings.vue @@ -1,5 +1,6 @@