misc fixes (#2961)

* fix backup reports modal

* chore: fix comments

---------

Co-authored-by: waterplea <alexander@inkin.ru>
This commit is contained in:
Matt Hill
2025-06-17 11:22:32 -06:00
committed by GitHub
parent 2464d255d5
commit f5688e077a
14 changed files with 279 additions and 242 deletions

210
web/package-lock.json generated
View File

@@ -25,19 +25,19 @@
"@noble/hashes": "^1.4.0", "@noble/hashes": "^1.4.0",
"@start9labs/argon2": "^0.3.0", "@start9labs/argon2": "^0.3.0",
"@start9labs/start-sdk": "file:../sdk/baseDist", "@start9labs/start-sdk": "file:../sdk/baseDist",
"@taiga-ui/addon-charts": "4.38.0", "@taiga-ui/addon-charts": "4.41.0",
"@taiga-ui/addon-commerce": "4.38.0", "@taiga-ui/addon-commerce": "4.41.0",
"@taiga-ui/addon-mobile": "4.38.0", "@taiga-ui/addon-mobile": "4.41.0",
"@taiga-ui/addon-table": "4.38.0", "@taiga-ui/addon-table": "4.41.0",
"@taiga-ui/cdk": "4.38.0", "@taiga-ui/cdk": "4.41.0",
"@taiga-ui/core": "4.38.0", "@taiga-ui/core": "4.41.0",
"@taiga-ui/dompurify": "4.1.11", "@taiga-ui/dompurify": "4.1.11",
"@taiga-ui/event-plugins": "4.5.1", "@taiga-ui/event-plugins": "4.6.0",
"@taiga-ui/experimental": "4.38.0", "@taiga-ui/experimental": "4.41.0",
"@taiga-ui/icons": "4.38.0", "@taiga-ui/icons": "4.41.0",
"@taiga-ui/kit": "4.38.0", "@taiga-ui/kit": "4.41.0",
"@taiga-ui/layout": "4.38.0", "@taiga-ui/layout": "4.41.0",
"@taiga-ui/legacy": "4.38.0", "@taiga-ui/legacy": "4.41.0",
"@taiga-ui/polymorpheus": "4.9.0", "@taiga-ui/polymorpheus": "4.9.0",
"ansi-to-html": "^0.7.2", "ansi-to-html": "^0.7.2",
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
@@ -3020,9 +3020,9 @@
] ]
}, },
"node_modules/@maskito/angular": { "node_modules/@maskito/angular": {
"version": "3.7.2", "version": "3.9.0",
"resolved": "https://registry.npmjs.org/@maskito/angular/-/angular-3.7.2.tgz", "resolved": "https://registry.npmjs.org/@maskito/angular/-/angular-3.9.0.tgz",
"integrity": "sha512-0auXz5dsS0pNuSZ3WFsQK3Fd6nucC9Um1WVlxoVbi0VEZZG68WirVQybwo7J5/J5gCDffqJn2bAw0qrbbrt0mQ==", "integrity": "sha512-vNKEa1Rc2xmtOEba75I4SrjFNE9oTPQemthvfTlkKDLYQYrKmlWBon1C5KKsMUv6zDLXnVhh0piT66fpNlJuUw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
@@ -3031,35 +3031,35 @@
"peerDependencies": { "peerDependencies": {
"@angular/core": ">=16.0.0", "@angular/core": ">=16.0.0",
"@angular/forms": ">=16.0.0", "@angular/forms": ">=16.0.0",
"@maskito/core": "^3.7.2" "@maskito/core": "^3.9.0"
} }
}, },
"node_modules/@maskito/core": { "node_modules/@maskito/core": {
"version": "3.7.2", "version": "3.9.0",
"resolved": "https://registry.npmjs.org/@maskito/core/-/core-3.7.2.tgz", "resolved": "https://registry.npmjs.org/@maskito/core/-/core-3.9.0.tgz",
"integrity": "sha512-jnX1u2HAZFy0K8Ll6AoeMpe502aVzrqgPKG7rk/qtbivW+71U3vutP3kqmjZtgsPoNzQ2wzKVWMgi7JEXDK11g==", "integrity": "sha512-OgzzgzJTXFZH79mqyHFVUZ5/bUhSW147+JzYVX+DdmQ5zc+mxmFQqsUS5ffVxd2C7/bnEmC7+savYbcae2IhBw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true "peer": true
}, },
"node_modules/@maskito/kit": { "node_modules/@maskito/kit": {
"version": "3.7.2", "version": "3.9.0",
"resolved": "https://registry.npmjs.org/@maskito/kit/-/kit-3.7.2.tgz", "resolved": "https://registry.npmjs.org/@maskito/kit/-/kit-3.9.0.tgz",
"integrity": "sha512-2gx/7k0iRcKWq7+2yeUEUuv13+4KibxkQrTdGSwZZVNbPsmj4b7r5KTbjfHl2ZdwuASSxJiVV8DWF91ON+cmBA==", "integrity": "sha512-CD7TQ7WUMtZ8jkhOsislbqht1gMuNHVQsLJG9tXcGvZbegkgJ6wdkggkol1y1/0F5eh/fT+RzzKD9dVjSQon2g==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true, "peer": true,
"peerDependencies": { "peerDependencies": {
"@maskito/core": "^3.7.2" "@maskito/core": "^3.9.0"
} }
}, },
"node_modules/@maskito/phone": { "node_modules/@maskito/phone": {
"version": "3.7.2", "version": "3.9.0",
"resolved": "https://registry.npmjs.org/@maskito/phone/-/phone-3.7.2.tgz", "resolved": "https://registry.npmjs.org/@maskito/phone/-/phone-3.9.0.tgz",
"integrity": "sha512-27KfVE9fR+NiwB35z03gPZ/UM+wJR5AfRYiMh37JZCXBz+/WRhtH3mntpzxmp0CCGoFTD/c3hBkCR9p5MAaxiQ==", "integrity": "sha512-EUCOmOscoQM+vnJwOAiBXVpZVVYkHc7rhnqLqfkslXsZCg5VLNNpzAb8SuFQMxYJYM2NnMawErvL7CjOdVDmvQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true, "peer": true,
"peerDependencies": { "peerDependencies": {
"@maskito/core": "^3.7.2", "@maskito/core": "^3.9.0",
"@maskito/kit": "^3.7.2", "@maskito/kit": "^3.9.0",
"libphonenumber-js": ">=1.0.0" "libphonenumber-js": ">=1.0.0"
} }
}, },
@@ -4719,9 +4719,9 @@
"link": true "link": true
}, },
"node_modules/@taiga-ui/addon-charts": { "node_modules/@taiga-ui/addon-charts": {
"version": "4.38.0", "version": "4.41.0",
"resolved": "https://registry.npmjs.org/@taiga-ui/addon-charts/-/addon-charts-4.38.0.tgz", "resolved": "https://registry.npmjs.org/@taiga-ui/addon-charts/-/addon-charts-4.41.0.tgz",
"integrity": "sha512-dJFGuekM7+2qxguqxOQIvFkqxkesbQlzU2cnLfiHzHXw7bsw6Sey8cc5lO2lqF3jsvRNVtmwgLtUY2wCkyxKog==", "integrity": "sha512-HksmSqKCQm2BXP5jhLXdFouZNru+0LFH0m5F22zbQ/6EG5uCttIztY+jcorcKqZzl29PEM8dFxg6EZe2JHYtlQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"tslib": ">=2.8.1" "tslib": ">=2.8.1"
@@ -4730,15 +4730,15 @@
"@angular/common": ">=16.0.0", "@angular/common": ">=16.0.0",
"@angular/core": ">=16.0.0", "@angular/core": ">=16.0.0",
"@ng-web-apis/common": "^4.12.0", "@ng-web-apis/common": "^4.12.0",
"@taiga-ui/cdk": "^4.38.0", "@taiga-ui/cdk": "^4.41.0",
"@taiga-ui/core": "^4.38.0", "@taiga-ui/core": "^4.41.0",
"@taiga-ui/polymorpheus": "^4.9.0" "@taiga-ui/polymorpheus": "^4.9.0"
} }
}, },
"node_modules/@taiga-ui/addon-commerce": { "node_modules/@taiga-ui/addon-commerce": {
"version": "4.38.0", "version": "4.41.0",
"resolved": "https://registry.npmjs.org/@taiga-ui/addon-commerce/-/addon-commerce-4.38.0.tgz", "resolved": "https://registry.npmjs.org/@taiga-ui/addon-commerce/-/addon-commerce-4.41.0.tgz",
"integrity": "sha512-rHMKFfuSisWvozBM8kgvwh9CxhaMsm0Ntcy3RPtF1WluUgfGRX2LSzLcBkFZpziW6qpwJyMB/8hbSJjK6p54dg==", "integrity": "sha512-f30Yidpx+J37E2/Iz+FKq9/IPL0uBb/pQXxseTKGSkFm3wiMvOVAHGdWsGrFts0aKbLG5Jv4RkfXp3HhXhy4cw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"tslib": ">=2.8.1" "tslib": ">=2.8.1"
@@ -4747,22 +4747,22 @@
"@angular/common": ">=16.0.0", "@angular/common": ">=16.0.0",
"@angular/core": ">=16.0.0", "@angular/core": ">=16.0.0",
"@angular/forms": ">=16.0.0", "@angular/forms": ">=16.0.0",
"@maskito/angular": "^3.7.2", "@maskito/angular": "^3.9.0",
"@maskito/core": "^3.7.2", "@maskito/core": "^3.9.0",
"@maskito/kit": "^3.7.2", "@maskito/kit": "^3.9.0",
"@ng-web-apis/common": "^4.12.0", "@ng-web-apis/common": "^4.12.0",
"@taiga-ui/cdk": "^4.38.0", "@taiga-ui/cdk": "^4.41.0",
"@taiga-ui/core": "^4.38.0", "@taiga-ui/core": "^4.41.0",
"@taiga-ui/i18n": "^4.38.0", "@taiga-ui/i18n": "^4.41.0",
"@taiga-ui/kit": "^4.38.0", "@taiga-ui/kit": "^4.41.0",
"@taiga-ui/polymorpheus": "^4.9.0", "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0" "rxjs": ">=7.0.0"
} }
}, },
"node_modules/@taiga-ui/addon-mobile": { "node_modules/@taiga-ui/addon-mobile": {
"version": "4.38.0", "version": "4.41.0",
"resolved": "https://registry.npmjs.org/@taiga-ui/addon-mobile/-/addon-mobile-4.38.0.tgz", "resolved": "https://registry.npmjs.org/@taiga-ui/addon-mobile/-/addon-mobile-4.41.0.tgz",
"integrity": "sha512-R5KbeeUW0ETPSqqxkRtDzbt01hL2dwJumpEzhRLP5bdeKW4Dw6C6BwuEyTpk5124BHchaQ1jyig6Ko2eoCX4Gw==", "integrity": "sha512-BgIMCvSFE+qezVvRJhmtPsuYUkiFa5mtuUTNTVE63dz+JqXciXcT3mbOFZpjEjTB8QWsPgYVZL6DCNnmuk0sIg==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"tslib": ">=2.8.1" "tslib": ">=2.8.1"
@@ -4772,18 +4772,18 @@
"@angular/common": ">=16.0.0", "@angular/common": ">=16.0.0",
"@angular/core": ">=16.0.0", "@angular/core": ">=16.0.0",
"@ng-web-apis/common": "^4.12.0", "@ng-web-apis/common": "^4.12.0",
"@taiga-ui/cdk": "^4.38.0", "@taiga-ui/cdk": "^4.41.0",
"@taiga-ui/core": "^4.38.0", "@taiga-ui/core": "^4.41.0",
"@taiga-ui/kit": "^4.38.0", "@taiga-ui/kit": "^4.41.0",
"@taiga-ui/layout": "^4.38.0", "@taiga-ui/layout": "^4.41.0",
"@taiga-ui/polymorpheus": "^4.9.0", "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0" "rxjs": ">=7.0.0"
} }
}, },
"node_modules/@taiga-ui/addon-table": { "node_modules/@taiga-ui/addon-table": {
"version": "4.38.0", "version": "4.41.0",
"resolved": "https://registry.npmjs.org/@taiga-ui/addon-table/-/addon-table-4.38.0.tgz", "resolved": "https://registry.npmjs.org/@taiga-ui/addon-table/-/addon-table-4.41.0.tgz",
"integrity": "sha512-vR6JR2P7CmRAx0OJ75q1km9u+JFn5ZgNjoc5C5ZuczG1qz2i8TGondmXadWhgBvI+X+soUW+iTpDeZEEsKYdIg==", "integrity": "sha512-kAlWqsBx6RGx2eeSON9bihyfSxu3MWtMAjFKW4vfzVrIEegtNODJmGJRc8dQYVwhHyId/qJil8aaWnJpXjCclw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"tslib": ">=2.8.1" "tslib": ">=2.8.1"
@@ -4792,18 +4792,18 @@
"@angular/common": ">=16.0.0", "@angular/common": ">=16.0.0",
"@angular/core": ">=16.0.0", "@angular/core": ">=16.0.0",
"@ng-web-apis/intersection-observer": "^4.12.0", "@ng-web-apis/intersection-observer": "^4.12.0",
"@taiga-ui/cdk": "^4.38.0", "@taiga-ui/cdk": "^4.41.0",
"@taiga-ui/core": "^4.38.0", "@taiga-ui/core": "^4.41.0",
"@taiga-ui/i18n": "^4.38.0", "@taiga-ui/i18n": "^4.41.0",
"@taiga-ui/kit": "^4.38.0", "@taiga-ui/kit": "^4.41.0",
"@taiga-ui/polymorpheus": "^4.9.0", "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0" "rxjs": ">=7.0.0"
} }
}, },
"node_modules/@taiga-ui/cdk": { "node_modules/@taiga-ui/cdk": {
"version": "4.38.0", "version": "4.41.0",
"resolved": "https://registry.npmjs.org/@taiga-ui/cdk/-/cdk-4.38.0.tgz", "resolved": "https://registry.npmjs.org/@taiga-ui/cdk/-/cdk-4.41.0.tgz",
"integrity": "sha512-L0SsDhrm7d0HE6Uw7ZJvP/s6UATUtW1ulfk19YxSuxIIdvLtfKWsJI2wG9nn3n3t7u+yaMFhnW20CCHqTPFoAw==", "integrity": "sha512-Oe6MQFut/bhnWK3U9J0u4iv+sGY8zXEXuyHScbMQhEe2a3g5XJjXXaBOngnp4jq2687PIQBtZcYvrM5/wcjXEw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"tslib": "2.8.1" "tslib": "2.8.1"
@@ -4826,15 +4826,15 @@
"@ng-web-apis/platform": "^4.12.0", "@ng-web-apis/platform": "^4.12.0",
"@ng-web-apis/resize-observer": "^4.12.0", "@ng-web-apis/resize-observer": "^4.12.0",
"@ng-web-apis/screen-orientation": "^4.12.0", "@ng-web-apis/screen-orientation": "^4.12.0",
"@taiga-ui/event-plugins": "^4.5.1", "@taiga-ui/event-plugins": "^4.6.0",
"@taiga-ui/polymorpheus": "^4.9.0", "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0" "rxjs": ">=7.0.0"
} }
}, },
"node_modules/@taiga-ui/core": { "node_modules/@taiga-ui/core": {
"version": "4.38.0", "version": "4.41.0",
"resolved": "https://registry.npmjs.org/@taiga-ui/core/-/core-4.38.0.tgz", "resolved": "https://registry.npmjs.org/@taiga-ui/core/-/core-4.41.0.tgz",
"integrity": "sha512-1xIfCBgjsVze/tjpjPNsHX0dvDLhFZdNtO3eCsEN8PVHAyeEDllefkScOjcMoMHQaXPjrIz65bRvhNg1aEd9bA==", "integrity": "sha512-ArND7zOBKlbGKdVrrsCWi3oZCkwmPCa3mS2wVD4JV0cq9N2KSw3KPp5mg77ZIEabIY9DM3ekXU8FDMyuhE3O2g==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"tslib": ">=2.8.1" "tslib": ">=2.8.1"
@@ -4848,9 +4848,9 @@
"@angular/router": ">=16.0.0", "@angular/router": ">=16.0.0",
"@ng-web-apis/common": "^4.12.0", "@ng-web-apis/common": "^4.12.0",
"@ng-web-apis/mutation-observer": "^4.12.0", "@ng-web-apis/mutation-observer": "^4.12.0",
"@taiga-ui/cdk": "^4.38.0", "@taiga-ui/cdk": "^4.41.0",
"@taiga-ui/event-plugins": "^4.5.1", "@taiga-ui/event-plugins": "^4.6.0",
"@taiga-ui/i18n": "^4.38.0", "@taiga-ui/i18n": "^4.41.0",
"@taiga-ui/polymorpheus": "^4.9.0", "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0" "rxjs": ">=7.0.0"
} }
@@ -4871,9 +4871,9 @@
} }
}, },
"node_modules/@taiga-ui/event-plugins": { "node_modules/@taiga-ui/event-plugins": {
"version": "4.5.1", "version": "4.6.0",
"resolved": "https://registry.npmjs.org/@taiga-ui/event-plugins/-/event-plugins-4.5.1.tgz", "resolved": "https://registry.npmjs.org/@taiga-ui/event-plugins/-/event-plugins-4.6.0.tgz",
"integrity": "sha512-p5TAs6ZAJAlyl64OUdvnVnfCvDteJtLl9cjXarMzPRY7sX2d+SC97qnTZF8ACPcx4FgFaiHI6VH5G6UzYHMZ8g==", "integrity": "sha512-5qshJXrwpJmsrdePjOofF8nr+6ONk7fXRdVG4MH0BGSLiV6ChwUm9K78ROjanVyI4vEkoFqBbh1bhS6DdJTwhA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"tslib": "^2.3.0" "tslib": "^2.3.0"
@@ -4885,9 +4885,9 @@
} }
}, },
"node_modules/@taiga-ui/experimental": { "node_modules/@taiga-ui/experimental": {
"version": "4.38.0", "version": "4.41.0",
"resolved": "https://registry.npmjs.org/@taiga-ui/experimental/-/experimental-4.38.0.tgz", "resolved": "https://registry.npmjs.org/@taiga-ui/experimental/-/experimental-4.41.0.tgz",
"integrity": "sha512-YjxZe5THRJwXi5cpUSvN9vOJT+ny5PpeSFR3oPTqn4x651wxdz6z6e/5BAhHg1+FKkOrV9F7PGQWuaw7UPrWVg==", "integrity": "sha512-X8mxCk2FN/sJpfB7bBeub+B2IMhOAogoh8fx/HDNspZfmKDpxLPYxJ+TosCrOyIA3nDtYpt3A2pmZ1cnxb11oQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"tslib": ">=2.8.1" "tslib": ">=2.8.1"
@@ -4895,18 +4895,18 @@
"peerDependencies": { "peerDependencies": {
"@angular/common": ">=16.0.0", "@angular/common": ">=16.0.0",
"@angular/core": ">=16.0.0", "@angular/core": ">=16.0.0",
"@taiga-ui/addon-commerce": "^4.38.0", "@taiga-ui/addon-commerce": "^4.41.0",
"@taiga-ui/cdk": "^4.38.0", "@taiga-ui/cdk": "^4.41.0",
"@taiga-ui/core": "^4.38.0", "@taiga-ui/core": "^4.41.0",
"@taiga-ui/kit": "^4.38.0", "@taiga-ui/kit": "^4.41.0",
"@taiga-ui/polymorpheus": "^4.9.0", "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0" "rxjs": ">=7.0.0"
} }
}, },
"node_modules/@taiga-ui/i18n": { "node_modules/@taiga-ui/i18n": {
"version": "4.38.0", "version": "4.41.0",
"resolved": "https://registry.npmjs.org/@taiga-ui/i18n/-/i18n-4.38.0.tgz", "resolved": "https://registry.npmjs.org/@taiga-ui/i18n/-/i18n-4.41.0.tgz",
"integrity": "sha512-mQ4akU8N3jU+ngkbx9DcLbArofdBq15WKuLEPame4rZvsf5IL3fxbAzFQkt2wmg2kRg125N1y3Ik04NtwgtwEg==", "integrity": "sha512-wvqOBf56eta1Q3RgRwKwmkj/HzvH4BVqOviN7QA4wN4q1e4BEh4N2k30CYuLr90Eoxo2+5fDaKGzE91INenbGA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true, "peer": true,
"dependencies": { "dependencies": {
@@ -4919,18 +4919,18 @@
} }
}, },
"node_modules/@taiga-ui/icons": { "node_modules/@taiga-ui/icons": {
"version": "4.38.0", "version": "4.41.0",
"resolved": "https://registry.npmjs.org/@taiga-ui/icons/-/icons-4.38.0.tgz", "resolved": "https://registry.npmjs.org/@taiga-ui/icons/-/icons-4.41.0.tgz",
"integrity": "sha512-XoY+jSMcsfRdsr7DkwMQcKeBXMdYU99SclW6lHuHZ2mjB7euhhKWOsqz4dIfB6jp0xPc/sN4RhrJPXBi/1ucDQ==", "integrity": "sha512-Zc9ufZiAhTfnly8eF1UW0138y1UnZfPZPhmNEd0BRObM6R+aK9EeYcIPE54SMNVzBLB4AtwmMJ/fCOU0VJbv3g==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"tslib": "^2.3.0" "tslib": "^2.3.0"
} }
}, },
"node_modules/@taiga-ui/kit": { "node_modules/@taiga-ui/kit": {
"version": "4.38.0", "version": "4.41.0",
"resolved": "https://registry.npmjs.org/@taiga-ui/kit/-/kit-4.38.0.tgz", "resolved": "https://registry.npmjs.org/@taiga-ui/kit/-/kit-4.41.0.tgz",
"integrity": "sha512-LJm6TO6T0qW7y2YYF/C+b0sJD8tr4MkBj3NZlwK7s4x172qj4nK9d5j4lt9+ik/6wdYpBH0twVwKWwasNqemqQ==", "integrity": "sha512-v27dmJtp05JQgwZhqRglc3iD7CYzW5R6ncBjmJKke556VlL1D1ruQSc2OYL4nUAt/dwaYYkpqhfBWwTbhehC6Q==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"tslib": ">=2.8.1" "tslib": ">=2.8.1"
@@ -4940,25 +4940,25 @@
"@angular/core": ">=16.0.0", "@angular/core": ">=16.0.0",
"@angular/forms": ">=16.0.0", "@angular/forms": ">=16.0.0",
"@angular/router": ">=16.0.0", "@angular/router": ">=16.0.0",
"@maskito/angular": "^3.7.2", "@maskito/angular": "^3.9.0",
"@maskito/core": "^3.7.2", "@maskito/core": "^3.9.0",
"@maskito/kit": "^3.7.2", "@maskito/kit": "^3.9.0",
"@maskito/phone": "^3.7.2", "@maskito/phone": "^3.9.0",
"@ng-web-apis/common": "^4.12.0", "@ng-web-apis/common": "^4.12.0",
"@ng-web-apis/intersection-observer": "^4.12.0", "@ng-web-apis/intersection-observer": "^4.12.0",
"@ng-web-apis/mutation-observer": "^4.12.0", "@ng-web-apis/mutation-observer": "^4.12.0",
"@ng-web-apis/resize-observer": "^4.12.0", "@ng-web-apis/resize-observer": "^4.12.0",
"@taiga-ui/cdk": "^4.38.0", "@taiga-ui/cdk": "^4.41.0",
"@taiga-ui/core": "^4.38.0", "@taiga-ui/core": "^4.41.0",
"@taiga-ui/i18n": "^4.38.0", "@taiga-ui/i18n": "^4.41.0",
"@taiga-ui/polymorpheus": "^4.9.0", "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0" "rxjs": ">=7.0.0"
} }
}, },
"node_modules/@taiga-ui/layout": { "node_modules/@taiga-ui/layout": {
"version": "4.38.0", "version": "4.41.0",
"resolved": "https://registry.npmjs.org/@taiga-ui/layout/-/layout-4.38.0.tgz", "resolved": "https://registry.npmjs.org/@taiga-ui/layout/-/layout-4.41.0.tgz",
"integrity": "sha512-x7D1MasJeh8tbMqpy2U9Uez9xbu6jiunGmhw/xEfZoYKsFprxOJkv/JJjPOTCHB/I3ou7RL1zDUHG3r453BOCQ==", "integrity": "sha512-czIU2suGUL6HqDjCKAYxSpyhOnVAtJLhhxt8MajS9mAuov1WzpBC85X3rqZsfc2x3j1XbCEuXyW43ns5994ilQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"tslib": ">=2.8.1" "tslib": ">=2.8.1"
@@ -4966,17 +4966,17 @@
"peerDependencies": { "peerDependencies": {
"@angular/common": ">=16.0.0", "@angular/common": ">=16.0.0",
"@angular/core": ">=16.0.0", "@angular/core": ">=16.0.0",
"@taiga-ui/cdk": "^4.38.0", "@taiga-ui/cdk": "^4.41.0",
"@taiga-ui/core": "^4.38.0", "@taiga-ui/core": "^4.41.0",
"@taiga-ui/kit": "^4.38.0", "@taiga-ui/kit": "^4.41.0",
"@taiga-ui/polymorpheus": "^4.9.0", "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0" "rxjs": ">=7.0.0"
} }
}, },
"node_modules/@taiga-ui/legacy": { "node_modules/@taiga-ui/legacy": {
"version": "4.38.0", "version": "4.41.0",
"resolved": "https://registry.npmjs.org/@taiga-ui/legacy/-/legacy-4.38.0.tgz", "resolved": "https://registry.npmjs.org/@taiga-ui/legacy/-/legacy-4.41.0.tgz",
"integrity": "sha512-TLGtI2ScezbhrWao60NqIrildy+qg5RtFkRiEUWRiB6loirJDloWv39jupi+KMfteN+nNGijQS9/UW3Jokw+Bw==", "integrity": "sha512-ezxG3iCnvs435f5pG5BvGhGAAScTr3bUOgCdKhEV7e/8MZUbZ4eUTi5RoBXzjBBBO87e1x7bJw8EGlUh2QbR4g==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"tslib": ">=2.8.1" "tslib": ">=2.8.1"
@@ -8155,9 +8155,9 @@
} }
}, },
"node_modules/libphonenumber-js": { "node_modules/libphonenumber-js": {
"version": "1.12.7", "version": "1.12.9",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.7.tgz", "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.9.tgz",
"integrity": "sha512-0nYZSNj/QEikyhcM5RZFXGlCB/mr4PVamnT1C2sKBnDDTYndrvbybYjvg+PMqAndQHlLbwQ3socolnL3WWTUFA==", "integrity": "sha512-VWwAdNeJgN7jFOD+wN4qx83DTPMVPPAUyx9/TUkBXKLiNkuWWk6anV0439tgdtwaJDrEdqkvdN22iA6J4bUCZg==",
"license": "MIT", "license": "MIT",
"peer": true "peer": true
}, },

View File

@@ -46,18 +46,18 @@
"@noble/hashes": "^1.4.0", "@noble/hashes": "^1.4.0",
"@start9labs/argon2": "^0.3.0", "@start9labs/argon2": "^0.3.0",
"@start9labs/start-sdk": "file:../sdk/baseDist", "@start9labs/start-sdk": "file:../sdk/baseDist",
"@taiga-ui/addon-charts": "4.38.0", "@taiga-ui/addon-charts": "4.41.0",
"@taiga-ui/addon-commerce": "4.38.0", "@taiga-ui/addon-commerce": "4.41.0",
"@taiga-ui/addon-mobile": "4.38.0", "@taiga-ui/addon-mobile": "4.41.0",
"@taiga-ui/addon-table": "4.38.0", "@taiga-ui/addon-table": "4.41.0",
"@taiga-ui/cdk": "4.38.0", "@taiga-ui/cdk": "4.41.0",
"@taiga-ui/core": "4.38.0", "@taiga-ui/core": "4.41.0",
"@taiga-ui/event-plugins": "4.5.1", "@taiga-ui/event-plugins": "4.6.0",
"@taiga-ui/experimental": "4.38.0", "@taiga-ui/experimental": "4.41.0",
"@taiga-ui/icons": "4.38.0", "@taiga-ui/icons": "4.41.0",
"@taiga-ui/kit": "4.38.0", "@taiga-ui/kit": "4.41.0",
"@taiga-ui/layout": "4.38.0", "@taiga-ui/layout": "4.41.0",
"@taiga-ui/legacy": "4.38.0", "@taiga-ui/legacy": "4.41.0",
"@taiga-ui/polymorpheus": "4.9.0", "@taiga-ui/polymorpheus": "4.9.0",
"@taiga-ui/dompurify": "4.1.11", "@taiga-ui/dompurify": "4.1.11",
"ansi-to-html": "^0.7.2", "ansi-to-html": "^0.7.2",

View File

@@ -17,20 +17,14 @@ import { StateService } from 'src/app/services/state.service'
@Component({ @Component({
template: ` template: `
<canvas matrix></canvas> <canvas matrix></canvas>
@if (stateService.kiosk) { <section tuiCardLarge>
<section tuiCardLarge> <h1 class="heading">
<h1 class="heading"> <tui-icon icon="@tui.circle-check-big" class="g-positive" />
<tui-icon icon="@tui.check-square" class="g-positive" /> Setup Complete!
Setup Complete! </h1>
</h1> @if (stateService.kiosk) {
<button tuiButton (click)="exitKiosk()">Continue to Login</button> <button tuiButton (click)="exitKiosk()">Continue to Login</button>
</section> } @else if (lanAddress) {
} @else if (lanAddress) {
<section tuiCardLarge>
<h1 class="heading">
<tui-icon icon="@tui.check-square" class="g-positive" />
Setup Complete!
</h1>
@if (stateService.setupType === 'restore') { @if (stateService.setupType === 'restore') {
<h3>You can now safely unplug your backup drive</h3> <h3>You can now safely unplug your backup drive</h3>
} @else if (stateService.setupType === 'transfer') { } @else if (stateService.setupType === 'transfer') {
@@ -65,8 +59,8 @@ import { StateService } from 'src/app/services/state.service'
</strong> </strong>
</a> </a>
<app-documentation hidden [lanAddress]="lanAddress" /> <app-documentation hidden [lanAddress]="lanAddress" />
</section> }
} </section>
`, `,
styles: ` styles: `
.heading { .heading {

View File

@@ -11,10 +11,10 @@ import { TuiDialogContext, TuiIcon, TuiTitle } from '@taiga-ui/core'
import { TuiCell } from '@taiga-ui/layout' import { TuiCell } from '@taiga-ui/layout'
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus' import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import { PatchDB } from 'patch-db-client' import { PatchDB } from 'patch-db-client'
import { scan } from 'rxjs' import { map } from 'rxjs'
import { BackupReport } from 'src/app/services/api/api.types' import { BackupReport } from 'src/app/services/api/api.types'
import { getManifest } from '../utils/get-package-data' import { getManifest } from '../utils/get-package-data'
import { T } from '@start9labs/start-sdk' import { DataModel } from '../services/patch-db/data-model'
@Component({ @Component({
template: ` template: `
@@ -56,7 +56,7 @@ import { T } from '@start9labs/start-sdk'
}) })
export class BackupsReportModal { export class BackupsReportModal {
private readonly i18n = inject(i18nPipe) private readonly i18n = inject(i18nPipe)
private readonly patch = inject(PatchDB) private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
readonly data = readonly data =
injectContext< injectContext<
@@ -65,13 +65,15 @@ export class BackupsReportModal {
readonly pkgTitles = toSignal( readonly pkgTitles = toSignal(
this.patch.watch$('packageData').pipe( this.patch.watch$('packageData').pipe(
scan<T.PackageDataEntry, Record<string, string>>((acc, pkg) => { map(allPkgs =>
const { id, title } = getManifest(pkg) Object.values(allPkgs).reduce<Record<string, string>>((acc, pkg) => {
return { const { id, title } = getManifest(pkg)
...acc, return {
[id]: title, ...acc,
} [id]: title,
}, {}), }
}, {}),
),
), ),
) )

View File

@@ -91,7 +91,7 @@ type ClearnetForm = {
<td [style.width.rem]="12"> <td [style.width.rem]="12">
{{ interface.value().addSsl ? (address.acme | acme) : '-' }} {{ interface.value().addSsl ? (address.acme | acme) : '-' }}
</td> </td>
<td>{{ address.url | mask }}</td> <td [style.order]="-1">{{ address.url | mask }}</td>
<td <td
actions actions
[href]="address.url" [href]="address.url"
@@ -102,7 +102,6 @@ type ClearnetForm = {
tuiIconButton tuiIconButton
iconStart="@tui.trash" iconStart="@tui.trash"
appearance="flat-grayscale" appearance="flat-grayscale"
[style.margin-inline-end.rem]="0.5"
(click)="remove(address)" (click)="remove(address)"
> >
{{ 'Delete' | i18n }} {{ 'Delete' | i18n }}
@@ -131,6 +130,19 @@ type ClearnetForm = {
</app-placeholder> </app-placeholder>
} }
`, `,
styles: `
:host-context(tui-root._mobile) {
td {
font-weight: bold;
color: var(--tui-text-primary);
&:first-child {
font-weight: normal;
color: var(--tui-text-secondary);
}
}
}
`,
host: { class: 'g-card' }, host: { class: 'g-card' },
imports: [ imports: [
TuiButton, TuiButton,

View File

@@ -6,6 +6,7 @@ import { i18nKey, i18nPipe } from '@start9labs/shared'
template: ` template: `
<thead> <thead>
<tr> <tr>
<ng-content select="th" />
@for (header of appTable(); track $index) { @for (header of appTable(); track $index) {
<th>{{ header | i18n }}</th> <th>{{ header | i18n }}</th>
} }

View File

@@ -1,3 +1,4 @@
import { NgTemplateOutlet } from '@angular/common'
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
@@ -16,44 +17,71 @@ import { NotificationsTableComponent } from './table.component'
@Component({ @Component({
template: ` template: `
<ng-container *title>{{ 'Notifications' | i18n }}</ng-container> <ng-container *title>
<h3 class="g-title"> {{ 'Notifications' | i18n }}
<button <ng-container *ngTemplateOutlet="button" />
appearance="primary" </ng-container>
iconEnd="@tui.chevron-down" <section class="g-card">
tuiButton <header>
size="xs" {{ 'Notifications' | i18n }}
type="button" <ng-container *ngTemplateOutlet="button" />
tuiDropdownAlign="right" </header>
tuiDropdownSided <table #table class="g-table" [notifications]="notifications()"></table>
[disabled]="!table.selected().length" <ng-template #button>
[tuiDropdown]="dropdown" <button
[tuiDropdownEnabled]="!!table.selected().length" appearance="primary"
[(tuiDropdownOpen)]="open" iconEnd="@tui.chevron-down"
> tuiButton
{{ 'Batch action' | i18n }} size="xs"
</button> type="button"
<ng-template #dropdown> tuiDropdownOpen
<tui-data-list> tuiDropdownAlign="right"
<button [tuiDropdown]="dropdown"
tuiOption [tuiDropdownEnabled]="!!table.selected().length"
(click)="markSeen(notifications(), table.selected())" [style.margin-inline-start]="'auto'"
> [disabled]="!table.selected().length"
{{ 'Mark seen' | i18n }} >
</button> {{ 'Batch action' | i18n }}
<button <ng-template #dropdown let-close>
tuiOption <tui-data-list (click)="close()">
(click)="markUnseen(notifications(), table.selected())" <button
> tuiOption
{{ 'Mark unseen' | i18n }} (click)="markSeen(notifications(), table.selected())"
</button> >
<button tuiOption (click)="remove(notifications(), table.selected())"> {{ 'Mark seen' | i18n }}
{{ 'Delete' | i18n }} </button>
</button> <button
</tui-data-list> tuiOption
(click)="markUnseen(notifications(), table.selected())"
>
{{ 'Mark unseen' | i18n }}
</button>
<button
tuiOption
(click)="remove(notifications(), table.selected())"
>
{{ 'Delete' | i18n }}
</button>
</tui-data-list>
</ng-template>
</button>
</ng-template> </ng-template>
</h3> </section>
<table #table class="g-table" [notifications]="notifications()"></table> `,
styles: `
:host {
padding: 1rem;
}
:host-context(tui-root._mobile) {
header {
display: none;
}
section {
padding-block: 0;
}
}
`, `,
host: { class: 'g-page' }, host: { class: 'g-page' },
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
@@ -64,6 +92,7 @@ import { NotificationsTableComponent } from './table.component'
NotificationsTableComponent, NotificationsTableComponent,
TitleDirective, TitleDirective,
i18nPipe, i18nPipe,
NgTemplateOutlet,
], ],
}) })
export default class NotificationsComponent implements OnInit { export default class NotificationsComponent implements OnInit {
@@ -75,8 +104,6 @@ export default class NotificationsComponent implements OnInit {
readonly errorService = inject(ErrorService) readonly errorService = inject(ErrorService)
readonly notifications = signal<ServerNotifications | undefined>(undefined) readonly notifications = signal<ServerNotifications | undefined>(undefined)
open = false
ngOnInit() { ngOnInit() {
this.route.queryParams.subscribe(params => { this.route.queryParams.subscribe(params => {
this.router.navigate([], { relativeTo: this.route, queryParams: {} }) this.router.navigate([], { relativeTo: this.route, queryParams: {} })
@@ -100,8 +127,6 @@ export default class NotificationsComponent implements OnInit {
current: ServerNotifications = [], current: ServerNotifications = [],
toUpdate: ServerNotifications = [], toUpdate: ServerNotifications = [],
) { ) {
this.open = false
this.notifications.set( this.notifications.set(
current.map(c => ({ current.map(c => ({
...c, ...c,
@@ -116,8 +141,6 @@ export default class NotificationsComponent implements OnInit {
current: ServerNotifications = [], current: ServerNotifications = [],
toUpdate: ServerNotifications = [], toUpdate: ServerNotifications = [],
) { ) {
this.open = false
this.notifications.set( this.notifications.set(
current.map(c => ({ current.map(c => ({
...c, ...c,
@@ -132,8 +155,6 @@ export default class NotificationsComponent implements OnInit {
current: ServerNotifications = [], current: ServerNotifications = [],
toDelete: ServerNotifications = [], toDelete: ServerNotifications = [],
) { ) {
this.open = false
this.notifications.set( this.notifications.set(
current.filter(c => !toDelete.some(n => n.id === c.id)), current.filter(c => !toDelete.some(n => n.id === c.id)),
) )

View File

@@ -10,7 +10,7 @@ import { RouterLink } from '@angular/router'
import { getPkgId, i18nPipe } from '@start9labs/shared' import { getPkgId, i18nPipe } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk' import { T } from '@start9labs/start-sdk'
import { TuiItem } from '@taiga-ui/cdk' import { TuiItem } from '@taiga-ui/cdk'
import { TuiButton, TuiLink } from '@taiga-ui/core' import { TuiButton, TuiLink, TuiTitle } from '@taiga-ui/core'
import { TuiBadge, TuiBreadcrumbs } from '@taiga-ui/kit' import { TuiBadge, TuiBreadcrumbs } from '@taiga-ui/kit'
import { TuiHeader } from '@taiga-ui/layout' import { TuiHeader } from '@taiga-ui/layout'
import { PatchDB } from 'patch-db-client' import { PatchDB } from 'patch-db-client'
@@ -41,7 +41,7 @@ import { TitleDirective } from 'src/app/services/title.service'
</tui-breadcrumbs> </tui-breadcrumbs>
@if (interface(); as value) { @if (interface(); as value) {
<header tuiHeader [style.margin-bottom.rem]="1"> <header tuiHeader [style.margin-bottom.rem]="1">
<hgroup> <hgroup tuiTitle>
<h3> <h3>
{{ value.name }} {{ value.name }}
<tui-badge size="l" [appearance]="getAppearance(value.type)"> <tui-badge size="l" [appearance]="getAppearance(value.type)">
@@ -60,7 +60,8 @@ import { TitleDirective } from 'src/app/services/title.service'
} }
`, `,
styles: ` styles: `
:host-context(tui-root._mobile) tui-breadcrumbs { :host-context(tui-root._mobile) tui-breadcrumbs,
:host-context(tui-root._mobile) h3 {
display: none; display: none;
} }
@@ -68,8 +69,6 @@ import { TitleDirective } from 'src/app/services/title.service'
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
margin: 1rem 0 0.5rem 0;
font-size: 2.4rem;
tui-badge { tui-badge {
text-transform: uppercase; text-transform: uppercase;
@@ -91,6 +90,7 @@ import { TitleDirective } from 'src/app/services/title.service'
i18nPipe, i18nPipe,
TuiBadge, TuiBadge,
TuiHeader, TuiHeader,
TuiTitle,
], ],
}) })
export default class ServiceInterfaceRoute { export default class ServiceInterfaceRoute {

View File

@@ -35,7 +35,7 @@ const ERROR =
{{ 'Network Folders' | i18n }} {{ 'Network Folders' | i18n }}
<tui-icon [tuiTooltip]="cifs" /> <tui-icon [tuiTooltip]="cifs" />
<ng-template #cifs><ng-content /></ng-template> <ng-template #cifs><ng-content /></ng-template>
<button tuiButton size="s" iconStart="@tui.plus" (click)="add()"> <button tuiButton size="xs" iconStart="@tui.plus" (click)="add()">
{{ 'Open New' | i18n }} {{ 'Open New' | i18n }}
</button> </button>
</header> </header>
@@ -100,11 +100,11 @@ const ERROR =
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga; @use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
tr { tr {
cursor: pointer;
@include taiga.transition(background); @include taiga.transition(background);
@media (taiga.$tui-mouse) { @media (taiga.$tui-mouse) {
&:hover { &:not(:has(app-placeholder)):hover {
cursor: pointer;
background: var(--tui-background-neutral-1-hover); background: var(--tui-background-neutral-1-hover);
} }
} }

View File

@@ -66,11 +66,11 @@ import { BackupStatusComponent } from './status.component'
@use '@taiga-ui/core/styles/taiga-ui-local' as taiga; @use '@taiga-ui/core/styles/taiga-ui-local' as taiga;
tr { tr {
cursor: pointer;
@include taiga.transition(background); @include taiga.transition(background);
@media (taiga.$tui-mouse) { @media (taiga.$tui-mouse) {
&:hover { &:not(:has(app-placeholder)):hover {
cursor: pointer;
background: var(--tui-background-neutral-1-hover); background: var(--tui-background-neutral-1-hover);
} }
} }

View File

@@ -46,7 +46,7 @@ import { SessionsTableComponent } from './table.component'
size="xs" size="xs"
appearance="primary-destructive" appearance="primary-destructive"
[style.margin-inline-start]="'auto'" [style.margin-inline-start]="'auto'"
[disabled]="!(sessions()?.selected$ | async)?.length" [disabled]="!sessions()?.selected()?.length"
(click)="terminate(others || [])" (click)="terminate(others || [])"
> >
{{ 'Terminate selected' | i18n }} {{ 'Terminate selected' | i18n }}
@@ -104,13 +104,16 @@ export default class SystemSessionsComponent {
) )
async terminate(all: readonly SessionWithId[]) { async terminate(all: readonly SessionWithId[]) {
const ids = this.sessions()?.selected$.value.map(s => s.id) || [] const ids =
this.sessions()
?.selected()
.map(s => s.id) || []
const loader = this.loader.open('Terminating sessions').subscribe() const loader = this.loader.open('Terminating sessions').subscribe()
try { try {
await this.api.killSessions({ ids }) await this.api.killSessions({ ids })
this.local$.next(all.filter(s => !ids.includes(s.id))) this.local$.next(all.filter(s => !ids.includes(s.id)))
this.sessions()?.selected$.next([]) this.sessions()?.selected.set([])
} catch (e: any) { } catch (e: any) {
this.errorService.handleError(e) this.errorService.handleError(e)
} finally { } finally {

View File

@@ -2,8 +2,11 @@ import { CommonModule } from '@angular/common'
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
computed,
input,
Input, Input,
OnChanges, OnChanges,
signal,
} from '@angular/core' } from '@angular/core'
import { FormsModule } from '@angular/forms' import { FormsModule } from '@angular/forms'
import { TuiIcon } from '@taiga-ui/core' import { TuiIcon } from '@taiga-ui/core'
@@ -17,17 +20,36 @@ import { i18nPipe } from '@start9labs/shared'
@Component({ @Component({
selector: '[sessions]', selector: '[sessions]',
template: ` template: `
<table [appTable]="['User Agent', 'Platform', 'Last Active']"> <table
@for (session of sessions; track $index) { [appTable]="
single()
? ['User Agent', 'Platform', 'Last Active']
: ['Platform', 'Last Active']
"
>
@if (!single()) {
<th [style.text-indent.rem]="1.75">
<input
tuiCheckbox
size="s"
type="checkbox"
[disabled]="!sessions()"
[ngModel]="all()"
(ngModelChange)="selected.set(($event && sessions()) || [])"
/>
{{ 'User Agent' | i18n }}
</th>
}
@for (session of sessions(); track $index) {
<tr> <tr>
<td [style.padding-left.rem]="single ? null : 2.5"> <td [style.padding-left.rem]="single() ? null : 2.5">
<label> <label>
@if (!single) { @if (!single()) {
<input <input
tuiCheckbox tuiCheckbox
size="s" size="s"
type="checkbox" type="checkbox"
[ngModel]="selected$.value.includes(session)" [ngModel]="selected().includes(session)"
(ngModelChange)="onToggle(session)" (ngModelChange)="onToggle(session)"
/> />
} }
@@ -43,12 +65,12 @@ import { i18nPipe } from '@start9labs/shared'
<td class="date">{{ session.lastActive | date: 'medium' }}</td> <td class="date">{{ session.lastActive | date: 'medium' }}</td>
</tr> </tr>
} @empty { } @empty {
@if (sessions) { @if (sessions()) {
<tr> <tr>
<td colspan="3">{{ 'No sessions' | i18n }}</td> <td colspan="3">{{ 'No sessions' | i18n }}</td>
</tr> </tr>
} @else { } @else {
@for (item of single ? [''] : ['', '']; track $index) { @for (item of single() ? [''] : ['', '']; track $index) {
<tr> <tr>
<td colspan="3"> <td colspan="3">
<div [tuiSkeleton]="true">{{ 'Loading' | i18n }}</div> <div [tuiSkeleton]="true">{{ 'Loading' | i18n }}</div>
@@ -144,25 +166,25 @@ import { i18nPipe } from '@start9labs/shared'
], ],
}) })
export class SessionsTableComponent<T extends Session> implements OnChanges { export class SessionsTableComponent<T extends Session> implements OnChanges {
readonly selected$ = new BehaviorSubject<readonly T[]>([]) readonly sessions = input<readonly T[] | null>(null)
readonly single = input(false)
@Input() readonly selected = signal<readonly T[]>([])
sessions: readonly T[] | null = null readonly all = computed(
() =>
@Input() !!this.selected()?.length &&
single = false (this.selected().length === this.sessions()?.length || null),
)
ngOnChanges() { ngOnChanges() {
this.selected$.next([]) this.selected.set([])
} }
onToggle(session: T) { onToggle(session: T) {
const selected = this.selected$.value if (this.selected().includes(session)) {
this.selected.update(selected => selected.filter(s => s !== session))
if (selected.includes(session)) {
this.selected$.next(selected.filter(s => s !== session))
} else { } else {
this.selected$.next([...selected, session]) this.selected.update(selected => [...selected, session])
} }
} }
} }

View File

@@ -29,7 +29,7 @@ import { TitleDirective } from 'src/app/services/title.service'
<interface-status [style.margin-left.rem]="0.5" [public]="public()" /> <interface-status [style.margin-left.rem]="0.5" [public]="public()" />
</ng-container> </ng-container>
<header tuiHeader> <header tuiHeader>
<hgroup> <hgroup tuiTitle>
<h3> <h3>
{{ iface.name }} {{ iface.name }}
<interface-status [public]="public()" /> <interface-status [public]="public()" />
@@ -41,20 +41,6 @@ import { TitleDirective } from 'src/app/services/title.service'
<app-interface [value]="ui" [isRunning]="true" /> <app-interface [value]="ui" [isRunning]="true" />
} }
`, `,
styles: `
h3 {
display: flex;
align-items: center;
gap: 0.5rem;
margin: 1rem 0 0.5rem 0;
font-size: 2.4rem;
tui-badge {
text-transform: uppercase;
font-weight: bold;
}
}
`,
host: { class: 'g-subpage' }, host: { class: 'g-subpage' },
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ imports: [
@@ -63,6 +49,7 @@ import { TitleDirective } from 'src/app/services/title.service'
TuiButton, TuiButton,
TitleDirective, TitleDirective,
TuiHeader, TuiHeader,
TuiTitle,
InterfaceStatusComponent, InterfaceStatusComponent,
i18nPipe, i18nPipe,
], ],

View File

@@ -87,12 +87,7 @@ hr {
padding: 0.5rem; padding: 0.5rem;
text-transform: capitalize; text-transform: capitalize;
box-shadow: 1px 0 var(--tui-border-normal); box-shadow: 1px 0 var(--tui-border-normal);
backdrop-filter: blur(1rem); background: var(--tui-background-base);
background-color: color-mix(
in hsl,
var(--tui-background-base) 90%,
transparent
);
} }
.g-card { .g-card {