diff --git a/package.json b/package.json index fc5ab689..ab4d56fe 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@stablelib/base64": "^2.0.1", "@stablelib/x25519": "^2.0.1", "@tanstack/query-core": "^5.100.14", - "@tanstack/react-virtual": "^3.13.25", + "@tanstack/react-virtual": "^3.13.26", "@tauri-apps/api": "^2.11.0", "@tauri-apps/plugin-clipboard-manager": "^2.3.2", "@tauri-apps/plugin-deep-link": "^2.4.9", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6ea7039e..b09b936b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -27,8 +27,8 @@ importers: specifier: ^5.100.14 version: 5.100.14 '@tanstack/react-virtual': - specifier: ^3.13.25 - version: 3.13.25(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + specifier: ^3.13.26 + version: 3.13.26(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@tauri-apps/api': specifier: ^2.11.0 version: 2.11.0 @@ -255,91 +255,91 @@ importers: packages: - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.3': - resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} engines: {node: '>=6.9.0'} - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} engines: {node: '>=6.9.0'} - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.29.2': - resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} engines: {node: '>=6.9.0'} - '@babel/parser@7.29.3': - resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + '@babel/plugin-transform-react-jsx-self@7.29.7': + resolution: {integrity: sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + '@babel/plugin-transform-react-jsx-source@7.29.7': + resolution: {integrity: sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.29.2': - resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} engines: {node: '>=6.9.0'} - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} engines: {node: '>=6.9.0'} '@biomejs/biome@2.4.15': @@ -1162,14 +1162,14 @@ packages: peerDependencies: react: ^18 || ^19 - '@tanstack/react-virtual@3.13.25': - resolution: {integrity: sha512-bmNoqMu6gcAW9JGrKVB0Q1tN1i5RONZF8r1fW0bbE4Oyf3DwEGnzzQJ2OW+Ozg1P4s8PyugkHg2ULZoFQN+cqw==} + '@tanstack/react-virtual@3.13.26': + resolution: {integrity: sha512-DosdgjOxCLahkn0o+ilmZYwEjo1glfMGuRT/j3PQ18yr5XqA8N/BCaL9IJ3B5TRl+nnzyK2IOFgAILwzN3a9xQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/virtual-core@3.15.0': - resolution: {integrity: sha512-0AwPGx0I8QxPYjAxShT/+z+ZOe9u8mW5rsXvivCTjRfRmz9a43+3mRyi4wwlyoUqOC56q/jatKa0Bh9M99BEHQ==} + '@tanstack/virtual-core@3.16.0': + resolution: {integrity: sha512-Er2N7q3WOiH6y2JLxsxNX+u2/sLqSsL0bxFgDjuiPiA7vKhZRm+IzcS17vRee3GNXr64UsesA5CAp9yTiIYw9A==} '@tauri-apps/api@2.11.0': resolution: {integrity: sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA==} @@ -1464,8 +1464,8 @@ packages: brace-expansion@1.1.14: resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} - brace-expansion@2.1.0: - resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} + brace-expansion@2.1.1: + resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} brace-expansion@5.0.6: resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} @@ -1806,8 +1806,8 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - es-toolkit@1.46.1: - resolution: {integrity: sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==} + es-toolkit@1.47.0: + resolution: {integrity: sha512-n1GuoD0WEQZMBk5tttoZSqwgyLx01oqa5XsBmCHwPyNe1S9jPBEmtR2pSgp2kJuWE3ciFZ6yRHmY4pM4C3OOkw==} esbuild@0.27.7: resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} @@ -3085,25 +3085,25 @@ packages: snapshots: - '@babel/code-frame@7.29.0': + '@babel/code-frame@7.29.7': dependencies: - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.29.3': {} + '@babel/compat-data@7.29.7': {} - '@babel/core@7.29.0': + '@babel/core@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -3113,91 +3113,91 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.29.1': + '@babel/generator@7.29.7': dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.28.6': + '@babel/helper-compilation-targets@7.29.7': dependencies: - '@babel/compat-data': 7.29.3 - '@babel/helper-validator-option': 7.27.1 + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 browserslist: 4.28.2 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-globals@7.28.0': {} + '@babel/helper-globals@7.29.7': {} - '@babel/helper-module-imports@7.28.6': + '@babel/helper-module-imports@7.29.7': dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/helper-plugin-utils@7.28.6': {} + '@babel/helper-plugin-utils@7.29.7': {} - '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.7': {} - '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@7.29.7': {} - '@babel/helper-validator-option@7.27.1': {} + '@babel/helper-validator-option@7.29.7': {} - '@babel/helpers@7.29.2': + '@babel/helpers@7.29.7': dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 - '@babel/parser@7.29.3': + '@babel/parser@7.29.7': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-react-jsx-self@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': + '@babel/plugin-transform-react-jsx-source@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 - '@babel/runtime@7.29.2': {} + '@babel/runtime@7.29.7': {} - '@babel/template@7.28.6': + '@babel/template@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 - '@babel/traverse@7.29.0': + '@babel/traverse@7.29.7': dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.29.0': + '@babel/types@7.29.7': dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 '@biomejs/biome@2.4.15': optionalDependencies: @@ -3236,8 +3236,8 @@ snapshots: '@emotion/babel-plugin@11.13.5': dependencies: - '@babel/helper-module-imports': 7.28.6 - '@babel/runtime': 7.29.2 + '@babel/helper-module-imports': 7.29.7 + '@babel/runtime': 7.29.7 '@emotion/hash': 0.9.2 '@emotion/memoize': 0.9.0 '@emotion/serialize': 1.3.3 @@ -3268,7 +3268,7 @@ snapshots: '@emotion/react@11.14.0(@types/react@19.2.15)(react@19.2.6)': dependencies: - '@babel/runtime': 7.29.2 + '@babel/runtime': 7.29.7 '@emotion/babel-plugin': 11.13.5 '@emotion/cache': 11.14.0 '@emotion/serialize': 1.3.3 @@ -3294,7 +3294,7 @@ snapshots: '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.15)(react@19.2.6))(@types/react@19.2.15)(react@19.2.6)': dependencies: - '@babel/runtime': 7.29.2 + '@babel/runtime': 7.29.7 '@emotion/babel-plugin': 11.13.5 '@emotion/is-prop-valid': 1.4.0 '@emotion/react': 11.14.0(@types/react@19.2.15)(react@19.2.6) @@ -3686,49 +3686,49 @@ snapshots: '@standard-schema/utils@0.3.0': {} - '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.29.0)': + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 - '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.29.0)': + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 - '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.29.0)': + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 - '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.29.0)': + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 - '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.29.0)': + '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 - '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.29.0)': + '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 - '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.29.0)': + '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 - '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.29.0)': + '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 + '@babel/core': 7.29.7 - '@svgr/babel-preset@8.1.0(@babel/core@7.29.0)': + '@svgr/babel-preset@8.1.0(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.29.0 - '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.29.0) - '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.29.0) - '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.29.0) - '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.29.0) - '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.29.0) - '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.29.0) - '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.29.0) - '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.29.0) + '@babel/core': 7.29.7 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.29.7) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.29.7) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.29.7) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.29.7) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.29.7) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.29.7) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.29.7) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.29.7) '@svgr/cli@8.1.0(typescript@6.0.3)': dependencies: @@ -3748,8 +3748,8 @@ snapshots: '@svgr/core@8.1.0(typescript@6.0.3)': dependencies: - '@babel/core': 7.29.0 - '@svgr/babel-preset': 8.1.0(@babel/core@7.29.0) + '@babel/core': 7.29.7 + '@svgr/babel-preset': 8.1.0(@babel/core@7.29.7) camelcase: 6.3.0 cosmiconfig: 8.3.6(typescript@6.0.3) snake-case: 3.0.4 @@ -3759,13 +3759,13 @@ snapshots: '@svgr/hast-util-to-babel-ast@8.0.0': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 entities: 4.5.0 '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@6.0.3))': dependencies: - '@babel/core': 7.29.0 - '@svgr/babel-preset': 8.1.0(@babel/core@7.29.0) + '@babel/core': 7.29.7 + '@svgr/babel-preset': 8.1.0(@babel/core@7.29.7) '@svgr/core': 8.1.0(typescript@6.0.3) '@svgr/hast-util-to-babel-ast': 8.0.0 svg-parser: 2.0.4 @@ -3862,13 +3862,13 @@ snapshots: '@tanstack/query-core': 5.100.14 react: 19.2.6 - '@tanstack/react-virtual@3.13.25(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@tanstack/react-virtual@3.13.26(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@tanstack/virtual-core': 3.15.0 + '@tanstack/virtual-core': 3.16.0 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - '@tanstack/virtual-core@3.15.0': {} + '@tanstack/virtual-core@3.16.0': {} '@tauri-apps/api@2.11.0': {} @@ -3965,24 +3965,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.29.0 + '@babel/types': 7.29.7 '@types/byte-size@8.1.2': {} @@ -4079,9 +4079,9 @@ snapshots: '@vitejs/plugin-react@5.2.0(vite@7.3.3(@types/node@25.9.1)(sass@1.92.1)(yaml@2.9.0))': dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@babel/core': 7.29.7 + '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7) '@rolldown/pluginutils': 1.0.0-rc.3 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 @@ -4133,7 +4133,7 @@ snapshots: babel-plugin-macros@3.1.0: dependencies: - '@babel/runtime': 7.29.2 + '@babel/runtime': 7.29.7 cosmiconfig: 7.1.0 resolve: 1.22.12 @@ -4152,7 +4152,7 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.1.0: + brace-expansion@2.1.1: dependencies: balanced-match: 1.0.2 @@ -4539,7 +4539,7 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - es-toolkit@1.46.1: {} + es-toolkit@1.47.0: {} esbuild@0.27.7: optionalDependencies: @@ -5230,7 +5230,7 @@ snapshots: minimatch@5.1.9: dependencies: - brace-expansion: 2.1.0 + brace-expansion: 2.1.1 motion-dom@12.40.0: dependencies: @@ -5334,7 +5334,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -5489,7 +5489,7 @@ snapshots: '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.2.15)(react@19.2.6)(redux@5.0.1))(react@19.2.6) clsx: 2.1.1 decimal.js-light: 2.5.1 - es-toolkit: 1.46.1 + es-toolkit: 1.47.0 eventemitter3: 5.0.4 immer: 10.2.0 react: 19.2.6 @@ -5926,7 +5926,7 @@ snapshots: use-deep-compare-effect@1.8.1(react@19.2.6): dependencies: - '@babel/runtime': 7.29.2 + '@babel/runtime': 7.29.7 dequal: 2.0.3 react: 19.2.6 diff --git a/src-tauri/.sqlx/query-1c996712f62a1005990733cd9eee7a94bdcf2ef01b559304aea1d642fab7ae22.json b/src-tauri/.sqlx/query-31e1b340bfbdf29dde642b657124a0705b638769ce6631c1b455cbf45e82bb14.json similarity index 50% rename from src-tauri/.sqlx/query-1c996712f62a1005990733cd9eee7a94bdcf2ef01b559304aea1d642fab7ae22.json rename to src-tauri/.sqlx/query-31e1b340bfbdf29dde642b657124a0705b638769ce6631c1b455cbf45e82bb14.json index 0da21a4f..004d36d0 100644 --- a/src-tauri/.sqlx/query-1c996712f62a1005990733cd9eee7a94bdcf2ef01b559304aea1d642fab7ae22.json +++ b/src-tauri/.sqlx/query-31e1b340bfbdf29dde642b657124a0705b638769ce6631c1b455cbf45e82bb14.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "DELETE FROM location WHERE id = $1;", + "query": "DELETE FROM location WHERE id = $1", "describe": { "columns": [], "parameters": { @@ -8,5 +8,5 @@ }, "nullable": [] }, - "hash": "1c996712f62a1005990733cd9eee7a94bdcf2ef01b559304aea1d642fab7ae22" + "hash": "31e1b340bfbdf29dde642b657124a0705b638769ce6631c1b455cbf45e82bb14" } diff --git a/src-tauri/.sqlx/query-3bedd8a0e3a8d4b76330ba0f81d82cf1590e6d15ba30360c41b0a5a3482df3df.json b/src-tauri/.sqlx/query-3bedd8a0e3a8d4b76330ba0f81d82cf1590e6d15ba30360c41b0a5a3482df3df.json new file mode 100644 index 00000000..9f7beee7 --- /dev/null +++ b/src-tauri/.sqlx/query-3bedd8a0e3a8d4b76330ba0f81d82cf1590e6d15ba30360c41b0a5a3482df3df.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT EXISTS (SELECT 1 FROM location WHERE service_location_mode <= $1)", + "describe": { + "columns": [ + { + "name": "EXISTS (SELECT 1 FROM location WHERE service_location_mode <= $1)", + "ordinal": 0, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false + ] + }, + "hash": "3bedd8a0e3a8d4b76330ba0f81d82cf1590e6d15ba30360c41b0a5a3482df3df" +} diff --git a/src-tauri/.sqlx/query-f88f92313f52f0b2c584f48b40e6edb4bc14d96f3000bd58a3ca68eecb8e4a88.json b/src-tauri/.sqlx/query-97a52a8bbf020b77afe5dc427efb66abfdc6b571d1631a4f77fbf4fa5cfbe7e7.json similarity index 94% rename from src-tauri/.sqlx/query-f88f92313f52f0b2c584f48b40e6edb4bc14d96f3000bd58a3ca68eecb8e4a88.json rename to src-tauri/.sqlx/query-97a52a8bbf020b77afe5dc427efb66abfdc6b571d1631a4f77fbf4fa5cfbe7e7.json index ee360eaf..e0c2aeee 100644 --- a/src-tauri/.sqlx/query-f88f92313f52f0b2c584f48b40e6edb4bc14d96f3000bd58a3ca68eecb8e4a88.json +++ b/src-tauri/.sqlx/query-97a52a8bbf020b77afe5dc427efb66abfdc6b571d1631a4f77fbf4fa5cfbe7e7.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT id \"id: _\", instance_id, name, address, pubkey, endpoint, allowed_ips, dns, network_id, route_all_traffic, keepalive_interval, location_mfa_mode \"location_mfa_mode: LocationMfaMode\", service_location_mode \"service_location_mode: ServiceLocationMode\",\n mfa_method \"mfa_method: _\", posture_check_required FROM location WHERE pubkey = $1;", + "query": "SELECT id \"id: _\", instance_id, name, address, pubkey, endpoint, allowed_ips, dns, network_id, route_all_traffic, keepalive_interval, location_mfa_mode \"location_mfa_mode: LocationMfaMode\", service_location_mode \"service_location_mode: ServiceLocationMode\",\n mfa_method \"mfa_method: _\", posture_check_required FROM location WHERE pubkey = $1", "describe": { "columns": [ { @@ -100,5 +100,5 @@ false ] }, - "hash": "f88f92313f52f0b2c584f48b40e6edb4bc14d96f3000bd58a3ca68eecb8e4a88" + "hash": "97a52a8bbf020b77afe5dc427efb66abfdc6b571d1631a4f77fbf4fa5cfbe7e7" } diff --git a/src-tauri/.sqlx/query-ba54bef9b71c2add858203b7be2c0e87d3a54d536ef96a923a6b949e16b9746e.json b/src-tauri/.sqlx/query-af70b9b18d8452a03d4d5624c2f3a11ab0d2e123989e97dfceb57e472523398c.json similarity index 67% rename from src-tauri/.sqlx/query-ba54bef9b71c2add858203b7be2c0e87d3a54d536ef96a923a6b949e16b9746e.json rename to src-tauri/.sqlx/query-af70b9b18d8452a03d4d5624c2f3a11ab0d2e123989e97dfceb57e472523398c.json index a8ba1030..a0a75036 100644 --- a/src-tauri/.sqlx/query-ba54bef9b71c2add858203b7be2c0e87d3a54d536ef96a923a6b949e16b9746e.json +++ b/src-tauri/.sqlx/query-af70b9b18d8452a03d4d5624c2f3a11ab0d2e123989e97dfceb57e472523398c.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "UPDATE location SET route_all_traffic = 0 WHERE instance_id = $1;", + "query": "UPDATE location SET route_all_traffic = 0 WHERE instance_id = $1", "describe": { "columns": [], "parameters": { @@ -8,5 +8,5 @@ }, "nullable": [] }, - "hash": "ba54bef9b71c2add858203b7be2c0e87d3a54d536ef96a923a6b949e16b9746e" + "hash": "af70b9b18d8452a03d4d5624c2f3a11ab0d2e123989e97dfceb57e472523398c" } diff --git a/src-tauri/.sqlx/query-49039d91cfdefbb32284d15af739a2090ba7baf9dee8cf00e8800b9a5f891fab.json b/src-tauri/.sqlx/query-c6a5e793cccc520039e28da8b4fb73e0c79c6a8d671c300ec2ea3eb0d58342b5.json similarity index 96% rename from src-tauri/.sqlx/query-49039d91cfdefbb32284d15af739a2090ba7baf9dee8cf00e8800b9a5f891fab.json rename to src-tauri/.sqlx/query-c6a5e793cccc520039e28da8b4fb73e0c79c6a8d671c300ec2ea3eb0d58342b5.json index c6b90053..2436bff9 100644 --- a/src-tauri/.sqlx/query-49039d91cfdefbb32284d15af739a2090ba7baf9dee8cf00e8800b9a5f891fab.json +++ b/src-tauri/.sqlx/query-c6a5e793cccc520039e28da8b4fb73e0c79c6a8d671c300ec2ea3eb0d58342b5.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT id, instance_id, name, address, pubkey, endpoint, allowed_ips, dns, network_id, route_all_traffic, keepalive_interval, location_mfa_mode \"location_mfa_mode: LocationMfaMode\", service_location_mode \"service_location_mode: ServiceLocationMode\", mfa_method \"mfa_method: _\", posture_check_required FROM location WHERE service_location_mode <= $1 ORDER BY name ASC;", + "query": "SELECT id, instance_id, name, address, pubkey, endpoint, allowed_ips, dns, network_id, route_all_traffic, keepalive_interval, location_mfa_mode \"location_mfa_mode: LocationMfaMode\", service_location_mode \"service_location_mode: ServiceLocationMode\", mfa_method \"mfa_method: _\", posture_check_required FROM location WHERE service_location_mode <= $1 ORDER BY name ASC", "describe": { "columns": [ { @@ -100,5 +100,5 @@ false ] }, - "hash": "49039d91cfdefbb32284d15af739a2090ba7baf9dee8cf00e8800b9a5f891fab" + "hash": "c6a5e793cccc520039e28da8b4fb73e0c79c6a8d671c300ec2ea3eb0d58342b5" } diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 70af8679..1015b0d5 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1431,7 +1431,7 @@ dependencies = [ "os_info", "prost", "regex", - "reqwest 0.13.3", + "reqwest 0.13.4", "rust-ini", "semver", "serde", @@ -1486,7 +1486,7 @@ dependencies = [ "defguard_wireguard_rs", "dirs-next", "prost", - "reqwest 0.13.3", + "reqwest 0.13.4", "serde", "serde_json", "thiserror 2.0.18", @@ -2723,9 +2723,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0" dependencies = [ "bytes", "itoa", @@ -3456,9 +3456,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" dependencies = [ "serde_core", "value-bag", @@ -3520,9 +3520,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "memoffset" @@ -5109,9 +5109,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" dependencies = [ "base64 0.22.1", "bytes", @@ -6143,18 +6143,18 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "struct-patch" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f19113e4a69e522707bfc091d0bf34def27cb734506a58e086288bec295093ac" +checksum = "be0dd3602dc475cc00732da8b54a79d1aec0843b3ecfa3a1efcbf8ff00e181a5" dependencies = [ "struct-patch-derive", ] [[package]] name = "struct-patch-derive" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65b68ee01d5cbcd4f403fd8a9cb4ad1af95debf22d66de15603afe3f74598e45" +checksum = "97409f38bb9816c7606c9ba860b2bb26f0bd1d5b4254b7fc26aa827af6af760c" dependencies = [ "proc-macro2", "quote", @@ -6398,7 +6398,7 @@ dependencies = [ "percent-encoding", "plist", "raw-window-handle", - "reqwest 0.13.3", + "reqwest 0.13.4", "serde", "serde_json", "serde_repr", diff --git a/src-tauri/src/bin/defguard-client.rs b/src-tauri/src/bin/defguard-client.rs index 782549bc..8925cd6f 100644 --- a/src-tauri/src/bin/defguard-client.rs +++ b/src-tauri/src/bin/defguard-client.rs @@ -34,7 +34,7 @@ use defguard_client::{ LOG_FILENAME, VERSION, }; use log::{Level, LevelFilter}; -use tauri::{AppHandle, Builder, Manager, RunEvent, WindowEvent}; +use tauri::{async_runtime, AppHandle, Builder, Manager, RunEvent, WindowEvent}; use tauri_plugin_deep_link::DeepLinkExt; use tauri_plugin_log::{Target, TargetKind}; @@ -100,7 +100,7 @@ async fn startup(app_handle: &AppHandle) { .lock() .expect("failed to lock app state") .mtu(); - let handle = tauri::async_runtime::spawn(async move { + let handle = async_runtime::spawn(async move { if let Err(err) = defguard_client::apple::sync_locations_and_tunnels(mtu).await { error!("Failed to sync locations and tunnels: {err}"); } @@ -122,7 +122,7 @@ async fn startup(app_handle: &AppHandle) { }); let handle = app_handle.clone(); - tauri::async_runtime::spawn(async move { + async_runtime::spawn(async move { defguard_client::apple::connection_state_update_thread(&handle).await; error!("Connection state update thread has exited unexpectedly, quitting the app."); handle.exit(0); @@ -131,7 +131,7 @@ async fn startup(app_handle: &AppHandle) { // Run periodic tasks. let periodic_tasks_handle = app_handle.clone(); - tauri::async_runtime::spawn(async move { + async_runtime::spawn(async move { run_periodic_tasks(&periodic_tasks_handle).await; // One of the tasks exited, so something went wrong, quit the app error!("One of the periodic tasks has stopped unexpectedly. Exiting the application."); @@ -154,6 +154,17 @@ async fn startup(app_handle: &AppHandle) { debug!("Tray menu has been re-generated successfully."); } +/// Open the appropriate window, either the old or the new UI, depending if there are locations. +#[cfg(not(target_os = "linux"))] +fn open_appropriate_window(app_handle: &AppHandle) { + let has_locations = async_runtime::block_on(has_non_service_locations()); + if has_locations { + let _ = WindowManager::open_tray(app_handle); + } else { + let _ = WindowManager::open_full_view(app_handle); + } +} + fn main() { let app = Builder::default() .invoke_handler(tauri::generate_handler![ @@ -220,14 +231,7 @@ fn main() { #[cfg(not(target_os = "linux"))] { - let has_locations = tauri::async_runtime::block_on( - defguard_client::window_manager::has_non_service_locations(), - ); - if has_locations { - let _ = WindowManager::open_tray(app); - } else { - let _ = WindowManager::open_full_view(app); - } + open_appropriate_window(app); } } })) @@ -370,12 +374,12 @@ fn main() { )?; // run DB migrations - tauri::async_runtime::block_on(handle_db_migrations()); + async_runtime::block_on(handle_db_migrations()); // Check if client needs to be initialized // and try to load provisioning config if necessary let provisioning_config = - tauri::async_runtime::block_on(handle_client_initialization(app_handle)); + async_runtime::block_on(handle_client_initialization(app_handle)); let state = AppState::new(config, provisioning_config); app.manage(state); @@ -395,7 +399,8 @@ fn main() { } #[cfg(not(target_os = "linux"))] { - // If the app was cold-launched by a deep link the full view must open, not the tray. + // If the app was cold-launched by a deep-link, the full view must open, not the + // tray. let launched_by_deep_link = app_handle .deep_link() .get_current() @@ -406,15 +411,7 @@ fn main() { info!("App launched via deep link, opening full view directly."); let _ = WindowManager::open_full_view(app_handle); } else { - let has_locations = tauri::async_runtime::block_on( - defguard_client::window_manager::has_non_service_locations() - ); - if has_locations { - WindowManager::open_tray(app_handle)?; - } else { - info!("No locations found, showing full view on startup."); - let _ = WindowManager::open_full_view(app_handle); - } + open_appropriate_window(app_handle); } } @@ -455,7 +452,7 @@ fn main() { log_dir.display(), service::config::DEFAULT_LOG_DIR ); - tauri::async_runtime::block_on(startup(app_handle)); + async_runtime::block_on(startup(app_handle)); // Handle a deep link that launched the app (startup case). if let Ok(Some(urls)) = app_handle.deep_link().get_current() { @@ -465,7 +462,7 @@ fn main() { // Handle Ctrl-C. debug!("Setting up Ctrl-C handler."); let app_handle_clone = app_handle.clone(); - tauri::async_runtime::spawn(async move { + async_runtime::spawn(async move { tokio::signal::ctrl_c() .await .expect("Signal handler failure"); @@ -490,7 +487,7 @@ fn main() { let semaphore = Arc::new(AtomicBool::new(false)); let semaphore_clone = Arc::clone(&semaphore); - let handle = tauri::async_runtime::spawn(async move { + let handle = async_runtime::spawn(async move { let _ = close_all_connections().await; // This will clean the database file, pruning write-ahead log. DB_POOL.close().await; @@ -499,19 +496,28 @@ fn main() { // Obj-C API needs a runtime, but at this point Tauri has closed its runtime, so // create a temporary one. defguard_client::apple::spawn_runloop_and_wait_for(&semaphore); - tauri::async_runtime::block_on(async move { + async_runtime::block_on(async move { let _ = handle.await; }); } #[cfg(not(target_os = "macos"))] { - tauri::async_runtime::block_on(async move { + async_runtime::block_on(async move { let _ = close_all_connections().await; // This will clean the database file, pruning write-ahead log. DB_POOL.close().await; }); } } + #[cfg(target_os = "macos")] + RunEvent::Reopen { + has_visible_windows, + .. + } => { + if !has_visible_windows { + open_appropriate_window(app_handle); + } + } _ => { trace!("Received event: {event:?}"); } diff --git a/src-tauri/src/database/models/location.rs b/src-tauri/src/database/models/location.rs index 85c470c3..543d480b 100644 --- a/src-tauri/src/database/models/location.rs +++ b/src-tauri/src/database/models/location.rs @@ -5,7 +5,7 @@ use std::str::FromStr; #[cfg(not(target_os = "macos"))] use defguard_wireguard_rs::{key::Key, net::IpAddrMask, peer::Peer, InterfaceConfiguration}; use serde::{Deserialize, Serialize}; -use sqlx::{prelude::Type, query, query_as, query_scalar, Error as SqlxError, SqliteExecutor}; +use sqlx::{prelude::Type, query, query_as, query_scalar, SqliteExecutor}; #[cfg(not(target_os = "macos"))] use super::wireguard_keys::WireguardKeys; @@ -129,7 +129,7 @@ impl Location { pub(crate) async fn all<'e, E>( executor: E, include_service_locations: bool, - ) -> Result, SqlxError> + ) -> sqlx::Result> where E: SqliteExecutor<'e>, { @@ -143,14 +143,34 @@ impl Location { service_location_mode \"service_location_mode: ServiceLocationMode\", \ mfa_method \"mfa_method: _\", posture_check_required \ FROM location WHERE service_location_mode <= $1 \ - ORDER BY name ASC;", + ORDER BY name ASC", max_service_location_mode ) .fetch_all(executor) .await } - pub(crate) async fn save<'e, E>(&mut self, executor: E) -> Result<(), SqlxError> + #[cfg(any(windows, target_os = "macos"))] + pub(crate) async fn exist<'e, E>( + executor: E, + include_service_locations: bool, + ) -> sqlx::Result + where + E: SqliteExecutor<'e>, + { + let max_service_location_mode = + Self::get_service_location_mode_filter(include_service_locations); + let result = query_scalar!( + "SELECT EXISTS (SELECT 1 FROM location WHERE service_location_mode <= $1)", + max_service_location_mode + ) + .fetch_one(executor) + .await?; + + Ok(result != 0) + } + + pub(crate) async fn save<'e, E>(&mut self, executor: E) -> sqlx::Result<()> where E: SqliteExecutor<'e>, { @@ -186,7 +206,7 @@ impl Location { pub(crate) async fn find_by_id<'e, E>( executor: E, location_id: Id, - ) -> Result, SqlxError> + ) -> sqlx::Result> where E: SqliteExecutor<'e>, { @@ -208,7 +228,7 @@ impl Location { executor: E, instance_id: Id, include_service_locations: bool, - ) -> Result, SqlxError> + ) -> sqlx::Result> where E: SqliteExecutor<'e>, { @@ -230,10 +250,7 @@ impl Location { .await } - pub(crate) async fn find_by_public_key<'e, E>( - executor: E, - pubkey: &str, - ) -> Result + pub(crate) async fn find_by_public_key<'e, E>(executor: E, pubkey: &str) -> sqlx::Result where E: SqliteExecutor<'e>, { @@ -244,18 +261,18 @@ impl Location { location_mfa_mode \"location_mfa_mode: LocationMfaMode\", \ service_location_mode \"service_location_mode: ServiceLocationMode\", mfa_method \"mfa_method: _\", posture_check_required \ - FROM location WHERE pubkey = $1;", + FROM location WHERE pubkey = $1", pubkey ) .fetch_one(executor) .await } - pub(crate) async fn delete<'e, E>(&self, executor: E) -> Result<(), SqlxError> + pub(crate) async fn delete<'e, E>(&self, executor: E) -> sqlx::Result<()> where E: SqliteExecutor<'e>, { - query!("DELETE FROM location WHERE id = $1;", self.id) + query!("DELETE FROM location WHERE id = $1", self.id) .execute(executor) .await?; Ok(()) @@ -270,7 +287,7 @@ impl Location { E: SqliteExecutor<'e>, { query!( - "UPDATE location SET route_all_traffic = 0 WHERE instance_id = $1;", + "UPDATE location SET route_all_traffic = 0 WHERE instance_id = $1", instance_id ) .execute(executor) @@ -401,7 +418,7 @@ impl Location { } impl Location { - pub(crate) async fn save<'e, E>(self, executor: E) -> Result, SqlxError> + pub(crate) async fn save<'e, E>(self, executor: E) -> sqlx::Result> where E: SqliteExecutor<'e>, { diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs index abedaeb9..5f941739 100644 --- a/src-tauri/src/tray.rs +++ b/src-tauri/src/tray.rs @@ -17,7 +17,7 @@ use crate::{ database::{models::location::Location, DB_POOL}, error::Error, events::EventKey, - window_manager::{show_new_ui_window_near_tray, NEW_UI_WINDOW_ID, OLD_UI_WINDOW_ID}, + window_manager::{show_new_ui_window, NEW_UI_WINDOW_ID, OLD_UI_WINDOW_ID}, ConnectionType, }; @@ -188,7 +188,7 @@ pub async fn setup_tray(app: &AppHandle) -> Result<(), Error> { if let Some(old_ui) = app.get_webview_window(OLD_UI_WINDOW_ID) { let _ = old_ui.hide(); } - show_new_ui_window_near_tray(app); + show_new_ui_window(app); } else { let _ = WindowManager::open_full_view(app); } @@ -258,7 +258,7 @@ pub fn handle_tray_menu_event(app: &AppHandle, event: MenuEvent) { info!("Received QUIT request. Initiating shutdown..."); handle.exit(0); } - TRAY_EVENT_SHOW => show_new_ui_window_near_tray(app), + TRAY_EVENT_SHOW => show_new_ui_window(app), TRAY_EVENT_HIDE => hide_visible_windows(app), TRAY_EVENT_UPDATES => { let _ = webbrowser::open(SUBSCRIBE_UPDATES_LINK); diff --git a/src-tauri/src/window_manager/mod.rs b/src-tauri/src/window_manager/mod.rs index 8ab01c07..be3d38c0 100644 --- a/src-tauri/src/window_manager/mod.rs +++ b/src-tauri/src/window_manager/mod.rs @@ -8,10 +8,7 @@ use crate::database::{models::location::Location, DB_POOL}; /// Returns `true` if there are any non-service locations in the database. #[cfg(not(target_os = "linux"))] pub async fn has_non_service_locations() -> bool { - match Location::all(&*DB_POOL, false).await { - Ok(locations) => !locations.is_empty(), - Err(_) => false, - } + Location::exist(&*DB_POOL, false).await.unwrap_or_default() } pub const NEW_UI_WINDOW_ID: &str = "new-ui"; @@ -89,6 +86,8 @@ impl WindowManager { #[cfg(target_os = "macos")] macos::position_window_near_tray(app, &window); #[cfg(target_os = "macos")] + let _ = app.set_dock_visibility(false); + #[cfg(target_os = "macos")] let _ = app.show(); let _ = window.show(); let _ = window.set_focus(); @@ -103,6 +102,8 @@ impl WindowManager { Self::build_full_window(app)? }; #[cfg(target_os = "macos")] + let _ = app.set_dock_visibility(true); + #[cfg(target_os = "macos")] let _ = app.show(); let _ = window.show(); let _ = window.set_focus(); @@ -123,10 +124,6 @@ pub(crate) fn show_new_ui_window(app: &AppHandle) { let _ = WindowManager::open_tray(app); } -pub(crate) fn show_new_ui_window_near_tray(app: &AppHandle) { - show_new_ui_window(app); -} - #[tauri::command] pub fn open_new_ui_window(app: AppHandle) { show_new_ui_window(&app); @@ -142,9 +139,6 @@ pub fn open_old_ui_window(app: AppHandle) { #[tauri::command] pub fn swap_to_old_ui(app: AppHandle) { tracing::info!("swap_to_old_ui called"); - #[cfg(target_os = "macos")] - let _ = app.set_dock_visibility(true); - if let Some(window) = tauri::Manager::get_webview_window(&app, NEW_UI_WINDOW_ID) { if let Err(err) = window.hide() { tracing::error!("swap_to_old_ui task: Failed to hide new-ui window: {err:?}"); @@ -175,9 +169,6 @@ pub fn close_tray_window(app: AppHandle) { #[tauri::command] pub fn swap_to_new_ui(app: AppHandle) { tracing::info!("swap_to_new_ui called"); - #[cfg(target_os = "macos")] - let _ = app.set_dock_visibility(false); - show_new_ui_window(&app); if let Some(window) = tauri::Manager::get_webview_window(&app, OLD_UI_WINDOW_ID) { if let Err(err) = window.hide() { diff --git a/src/shared/images/png/logo_256-256.png b/src/shared/images/png/logo_256-256.png index a18d538b..12f44fde 100644 Binary files a/src/shared/images/png/logo_256-256.png and b/src/shared/images/png/logo_256-256.png differ