diff --git a/web/package-lock.json b/web/package-lock.json
index 26b9d7c95..39a3138f0 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -25,17 +25,17 @@
"@noble/hashes": "^1.4.0",
"@start9labs/argon2": "^0.2.2",
"@start9labs/start-sdk": "file:../sdk/baseDist",
- "@taiga-ui/addon-charts": "4.28.0",
- "@taiga-ui/addon-commerce": "4.28.0",
- "@taiga-ui/addon-mobile": "4.28.0",
- "@taiga-ui/addon-table": "4.28.0",
- "@taiga-ui/cdk": "4.28.0",
- "@taiga-ui/core": "4.28.0",
- "@taiga-ui/event-plugins": "4.4.1",
- "@taiga-ui/icons": "4.28.0",
- "@taiga-ui/kit": "4.28.0",
- "@taiga-ui/layout": "4.28.0",
- "@taiga-ui/legacy": "4.28.0",
+ "@taiga-ui/addon-charts": "4.30.0",
+ "@taiga-ui/addon-commerce": "4.30.0",
+ "@taiga-ui/addon-mobile": "4.30.0",
+ "@taiga-ui/addon-table": "4.30.0",
+ "@taiga-ui/cdk": "4.30.0",
+ "@taiga-ui/core": "4.30.0",
+ "@taiga-ui/event-plugins": "4.5.0",
+ "@taiga-ui/icons": "4.30.0",
+ "@taiga-ui/kit": "4.30.0",
+ "@taiga-ui/layout": "4.30.0",
+ "@taiga-ui/legacy": "4.30.0",
"@taiga-ui/polymorpheus": "4.9.0",
"@tinkoff/ng-dompurify": "4.0.0",
"ansi-to-html": "^0.7.2",
@@ -3422,9 +3422,9 @@
}
},
"node_modules/@maskito/angular": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/@maskito/angular/-/angular-3.4.0.tgz",
- "integrity": "sha512-iMFP/siEgU9Ki+g1PReZlA5+LlBMp6inqXGG5KCezhmDleZnG5lL9gxk3+ktJvKu+2kayLcwyBeUKXPwMBVt9w==",
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/@maskito/angular/-/angular-3.5.0.tgz",
+ "integrity": "sha512-5uwar32qsGdZNHUgZpFnICg9tJKCXbZEGk2ZnchHzDIfN5ojNT7wKzoq8NhpRlGb3p4qQCE+PXb5GERkcWM/Sw==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
@@ -3433,35 +3433,35 @@
"peerDependencies": {
"@angular/core": ">=16.0.0",
"@angular/forms": ">=16.0.0",
- "@maskito/core": "^3.4.0"
+ "@maskito/core": "^3.5.0"
}
},
"node_modules/@maskito/core": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/@maskito/core/-/core-3.4.0.tgz",
- "integrity": "sha512-gFM6qk675YwOEGhxu9Xm6/sl1TZBRab6+B3Gstqml7xJopHHZ0rUOrWXwmX0z2JI+1PsgUL/ftV/CSZ8CpIONg==",
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/@maskito/core/-/core-3.5.0.tgz",
+ "integrity": "sha512-zgmBjXeXc7BSBaw8jQw25dnwkFmKDvdj5rHzhEIxYhgGtnpli236F0YWPIOYzIwADjbefwDq1o7qpJfMsdDO4Q==",
"license": "Apache-2.0",
"peer": true
},
"node_modules/@maskito/kit": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/@maskito/kit/-/kit-3.4.0.tgz",
- "integrity": "sha512-jkexr7wjAqFeMpyc7s0IlinL+3F9xC4BYUHDQcEqlAJisDgVFtGCZZK/RvV1C+HGDn2gtzzVrJ3G/OY66k6EXg==",
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/@maskito/kit/-/kit-3.5.0.tgz",
+ "integrity": "sha512-QnpZsPTINgK4ScA4pMMJagoj+ufIXc/VGOP61AsQa/H/lmXII4pEZTLzpmMNUYmCEIEyjHR2DIbfEed04sktvQ==",
"license": "Apache-2.0",
"peer": true,
"peerDependencies": {
- "@maskito/core": "^3.4.0"
+ "@maskito/core": "^3.5.0"
}
},
"node_modules/@maskito/phone": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/@maskito/phone/-/phone-3.4.0.tgz",
- "integrity": "sha512-KR6JuuWhTumIOCUV3CzPhh1niCXcuqsogNsLW3YfdmeVo8GygS9isnHNbSaAA/b9OnmIEkh25mur6x3yEJuYjA==",
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/@maskito/phone/-/phone-3.5.0.tgz",
+ "integrity": "sha512-qh/GGRFn8cZBY/JUTLa5yeSSKSVlekggKeiCbf0eX0I53/HM2pNZ/5667S8SXwn5WjIEeB79Eltl8MNvK74yvA==",
"license": "Apache-2.0",
"peer": true,
"peerDependencies": {
- "@maskito/core": "^3.4.0",
- "@maskito/kit": "^3.4.0",
+ "@maskito/core": "^3.5.0",
+ "@maskito/kit": "^3.5.0",
"libphonenumber-js": ">=1.0.0"
}
},
@@ -4417,9 +4417,9 @@
"link": true
},
"node_modules/@taiga-ui/addon-charts": {
- "version": "4.28.0",
- "resolved": "https://registry.npmjs.org/@taiga-ui/addon-charts/-/addon-charts-4.28.0.tgz",
- "integrity": "sha512-Lvi2R8Y50kBbfbru31YHon+CEpnOzAx0G4GnqjN2goTLNQ6iX7pgUeyRyiXI4ay1yLrzVIOZJhSmBwWSDocZEg==",
+ "version": "4.30.0",
+ "resolved": "https://registry.npmjs.org/@taiga-ui/addon-charts/-/addon-charts-4.30.0.tgz",
+ "integrity": "sha512-QrM2Oh4hUcg/I0K3KWFkc/dbTCYZn2n5GU2FSpZaK6I7pwjfRoMjBU7vswPLVVdmgeWTJxxoQlbfYnbUbkMAJw==",
"license": "Apache-2.0",
"dependencies": {
"tslib": ">=2.8.1"
@@ -4428,15 +4428,15 @@
"@angular/common": ">=16.0.0",
"@angular/core": ">=16.0.0",
"@ng-web-apis/common": "^4.11.1",
- "@taiga-ui/cdk": "^4.28.0",
- "@taiga-ui/core": "^4.28.0",
- "@taiga-ui/polymorpheus": "^4.8.0"
+ "@taiga-ui/cdk": "^4.30.0",
+ "@taiga-ui/core": "^4.30.0",
+ "@taiga-ui/polymorpheus": "^4.9.0"
}
},
"node_modules/@taiga-ui/addon-commerce": {
- "version": "4.28.0",
- "resolved": "https://registry.npmjs.org/@taiga-ui/addon-commerce/-/addon-commerce-4.28.0.tgz",
- "integrity": "sha512-VYygBL7oySCZYLBimGJPx/VGGtUGhpes3XwBHAPBmmyiVxct0kxXzhCQdAvNMQcSvDzXDBjg3wmJiUbZA/uHGQ==",
+ "version": "4.30.0",
+ "resolved": "https://registry.npmjs.org/@taiga-ui/addon-commerce/-/addon-commerce-4.30.0.tgz",
+ "integrity": "sha512-6diktxvxMpWjbEHXThS0pTrURdUiF/47jf2jdBFkMwX3BbbekisM1qkwxY24V7q8fN0IIxfO8CVEjTeLRrCw5g==",
"license": "Apache-2.0",
"dependencies": {
"tslib": ">=2.8.1"
@@ -4445,22 +4445,22 @@
"@angular/common": ">=16.0.0",
"@angular/core": ">=16.0.0",
"@angular/forms": ">=16.0.0",
- "@maskito/angular": "^3.4.0",
- "@maskito/core": "^3.4.0",
- "@maskito/kit": "^3.4.0",
+ "@maskito/angular": "^3.5.0",
+ "@maskito/core": "^3.5.0",
+ "@maskito/kit": "^3.5.0",
"@ng-web-apis/common": "^4.11.1",
- "@taiga-ui/cdk": "^4.28.0",
- "@taiga-ui/core": "^4.28.0",
- "@taiga-ui/i18n": "^4.28.0",
- "@taiga-ui/kit": "^4.28.0",
- "@taiga-ui/polymorpheus": "^4.8.0",
+ "@taiga-ui/cdk": "^4.30.0",
+ "@taiga-ui/core": "^4.30.0",
+ "@taiga-ui/i18n": "^4.30.0",
+ "@taiga-ui/kit": "^4.30.0",
+ "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0"
}
},
"node_modules/@taiga-ui/addon-mobile": {
- "version": "4.28.0",
- "resolved": "https://registry.npmjs.org/@taiga-ui/addon-mobile/-/addon-mobile-4.28.0.tgz",
- "integrity": "sha512-1RRaX37Ddl24q4nHrMEz6iDqHWi/mkTyXQ+kADX7+ydx9JkbU2H4R+qXrOx4+GUi93Y05HvAWCNCToBu3Ytt2A==",
+ "version": "4.30.0",
+ "resolved": "https://registry.npmjs.org/@taiga-ui/addon-mobile/-/addon-mobile-4.30.0.tgz",
+ "integrity": "sha512-8cYyU0UDLUd74v+Zjs4m9S4AsSWchUojAexDLvaAHzfi0x+tdtA+ZN0h49v8AmOWHK0v69z4FMjyyc52p/jiDw==",
"license": "Apache-2.0",
"dependencies": {
"tslib": ">=2.8.1"
@@ -4470,18 +4470,18 @@
"@angular/common": ">=16.0.0",
"@angular/core": ">=16.0.0",
"@ng-web-apis/common": "^4.11.1",
- "@taiga-ui/cdk": "^4.28.0",
- "@taiga-ui/core": "^4.28.0",
- "@taiga-ui/kit": "^4.28.0",
- "@taiga-ui/layout": "^4.28.0",
- "@taiga-ui/polymorpheus": "^4.8.0",
+ "@taiga-ui/cdk": "^4.30.0",
+ "@taiga-ui/core": "^4.30.0",
+ "@taiga-ui/kit": "^4.30.0",
+ "@taiga-ui/layout": "^4.30.0",
+ "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0"
}
},
"node_modules/@taiga-ui/addon-table": {
- "version": "4.28.0",
- "resolved": "https://registry.npmjs.org/@taiga-ui/addon-table/-/addon-table-4.28.0.tgz",
- "integrity": "sha512-C8MW6kJ3T9zy51rSxqYApll+S84oizK6C85gZyDM3gEV2RAlK2DP+r657ZlEwEgobrFCtBZe++TT7ZoKpQBBHg==",
+ "version": "4.30.0",
+ "resolved": "https://registry.npmjs.org/@taiga-ui/addon-table/-/addon-table-4.30.0.tgz",
+ "integrity": "sha512-OdCEwlrMs42Z2pINK1wvNk7OZmAlkj+mbgHTyMGdrUdA49dFZfYXNpVUCwVOqHAm2PDOeVN4ybZ8FSbzYefJyw==",
"license": "Apache-2.0",
"dependencies": {
"tslib": ">=2.8.1"
@@ -4490,18 +4490,18 @@
"@angular/common": ">=16.0.0",
"@angular/core": ">=16.0.0",
"@ng-web-apis/intersection-observer": "^4.11.1",
- "@taiga-ui/cdk": "^4.28.0",
- "@taiga-ui/core": "^4.28.0",
- "@taiga-ui/i18n": "^4.28.0",
- "@taiga-ui/kit": "^4.28.0",
- "@taiga-ui/polymorpheus": "^4.8.0",
+ "@taiga-ui/cdk": "^4.30.0",
+ "@taiga-ui/core": "^4.30.0",
+ "@taiga-ui/i18n": "^4.30.0",
+ "@taiga-ui/kit": "^4.30.0",
+ "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0"
}
},
"node_modules/@taiga-ui/cdk": {
- "version": "4.28.0",
- "resolved": "https://registry.npmjs.org/@taiga-ui/cdk/-/cdk-4.28.0.tgz",
- "integrity": "sha512-P2vK+4WDnSt/nnilqxvDS4lyMAEH/M73z9YSzyH5mEwVTNxD3m82jJgpHqV5Re7geooAyaKqS6MJwDxaN0+9eQ==",
+ "version": "4.30.0",
+ "resolved": "https://registry.npmjs.org/@taiga-ui/cdk/-/cdk-4.30.0.tgz",
+ "integrity": "sha512-ndfnLOnL6vriItm5lq8/0slzj03CatkGVYG8zAT3fx00Vuam5Wf8Sh6h2ObqCFAljT7WJxHqMF9A1cBfLPI/iQ==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "2.8.1"
@@ -4525,14 +4525,14 @@
"@ng-web-apis/resize-observer": "^4.11.1",
"@ng-web-apis/screen-orientation": "^4.11.1",
"@taiga-ui/event-plugins": "^4.4.1",
- "@taiga-ui/polymorpheus": "^4.8.0",
+ "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0"
}
},
"node_modules/@taiga-ui/core": {
- "version": "4.28.0",
- "resolved": "https://registry.npmjs.org/@taiga-ui/core/-/core-4.28.0.tgz",
- "integrity": "sha512-4eP6PJvmHZCrV/9apxfu6Bgj7L72yjVg1R5c4j1MsVmMESLCCRGlk0hPPvuxVQ+ZYrOZwNeWyKHPZDPL5uQawA==",
+ "version": "4.30.0",
+ "resolved": "https://registry.npmjs.org/@taiga-ui/core/-/core-4.30.0.tgz",
+ "integrity": "sha512-IeZ6QBpSuv7k4bQx2BSDr8N3dDiMDwgnnwkkKqtJ0yJayZ/ZlCMq3nUQA0kg3VjH2spJeUbdqkDqpEuzrWJGkA==",
"license": "Apache-2.0",
"dependencies": {
"tslib": ">=2.8.1"
@@ -4546,17 +4546,17 @@
"@angular/router": ">=16.0.0",
"@ng-web-apis/common": "^4.11.1",
"@ng-web-apis/mutation-observer": "^4.11.1",
- "@taiga-ui/cdk": "^4.28.0",
+ "@taiga-ui/cdk": "^4.30.0",
"@taiga-ui/event-plugins": "^4.4.1",
- "@taiga-ui/i18n": "^4.28.0",
- "@taiga-ui/polymorpheus": "^4.8.0",
+ "@taiga-ui/i18n": "^4.30.0",
+ "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0"
}
},
"node_modules/@taiga-ui/event-plugins": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/@taiga-ui/event-plugins/-/event-plugins-4.4.1.tgz",
- "integrity": "sha512-gwEkgyZsbAdRfmb98KlKWivYVF88eP0bOtbHwfj8Ec8DgJ5809qFqeWvJEIxZZ829iox1m8z2UuVrqN2/tI1tQ==",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/@taiga-ui/event-plugins/-/event-plugins-4.5.0.tgz",
+ "integrity": "sha512-bMW36eqr4Q+EnUM8ZNjx1Sw8POIAcyALY74xVPq9UHoQ3NqnRkeEDnZdfPhq9IYxtC3sO2BttNjWYcvBAkU2+A==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.3.0"
@@ -4568,9 +4568,9 @@
}
},
"node_modules/@taiga-ui/i18n": {
- "version": "4.28.0",
- "resolved": "https://registry.npmjs.org/@taiga-ui/i18n/-/i18n-4.28.0.tgz",
- "integrity": "sha512-kM7bbqllzir4nEk3X+YMKATm23UoKJeWSGmwnjLEmhWkpNAGqfErDRbE2puf+jXy7eufGhaB7ht/mK4+HkLXbw==",
+ "version": "4.30.0",
+ "resolved": "https://registry.npmjs.org/@taiga-ui/i18n/-/i18n-4.30.0.tgz",
+ "integrity": "sha512-OvtUqSRQE988XfiH1MS7Wd3Eg6dE1mkP2sqYRLw0HyE5Oc9hgHMwdPstSaoMN9aeJRVZnKXGsYmX4iaQ3x7drw==",
"license": "Apache-2.0",
"peer": true,
"dependencies": {
@@ -4583,18 +4583,18 @@
}
},
"node_modules/@taiga-ui/icons": {
- "version": "4.28.0",
- "resolved": "https://registry.npmjs.org/@taiga-ui/icons/-/icons-4.28.0.tgz",
- "integrity": "sha512-1QS7gvYHuTRUUodE58OXm+4Ree5FhFe0co0Lj+3sqeqkYb495z5q3CXBNiXD3y8IcDTjNuYkxKxEthbPnQrsVQ==",
+ "version": "4.30.0",
+ "resolved": "https://registry.npmjs.org/@taiga-ui/icons/-/icons-4.30.0.tgz",
+ "integrity": "sha512-EAbvw1ii4UVDgt9+5t7NQkV0WBqkVm5SGixH0ux8Vb4qhhLJJwp5xvXOCGt5QPzviT7nFGqXD6EqB23aYcuusg==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.3.0"
}
},
"node_modules/@taiga-ui/kit": {
- "version": "4.28.0",
- "resolved": "https://registry.npmjs.org/@taiga-ui/kit/-/kit-4.28.0.tgz",
- "integrity": "sha512-JEHUZhWU0vgPorvO3l9POzWKPbFQA57jFh9Iv5/RlWxMI8EUI+OKH5J8z1ptX+RJE2dWB9+Yi84zasgr8TWcSA==",
+ "version": "4.30.0",
+ "resolved": "https://registry.npmjs.org/@taiga-ui/kit/-/kit-4.30.0.tgz",
+ "integrity": "sha512-tCHZbsiq1u19ariarFuP9iwnNSxJGicQnYvJYy2+QojL65KsC9p8VgZv36rpggpuPEUXRXwmhyz2Qi6fwFcbLg==",
"license": "Apache-2.0",
"dependencies": {
"tslib": ">=2.8.1"
@@ -4604,25 +4604,25 @@
"@angular/core": ">=16.0.0",
"@angular/forms": ">=16.0.0",
"@angular/router": ">=16.0.0",
- "@maskito/angular": "^3.4.0",
- "@maskito/core": "^3.4.0",
- "@maskito/kit": "^3.4.0",
- "@maskito/phone": "^3.4.0",
+ "@maskito/angular": "^3.5.0",
+ "@maskito/core": "^3.5.0",
+ "@maskito/kit": "^3.5.0",
+ "@maskito/phone": "^3.5.0",
"@ng-web-apis/common": "^4.11.1",
"@ng-web-apis/intersection-observer": "^4.11.1",
"@ng-web-apis/mutation-observer": "^4.11.1",
"@ng-web-apis/resize-observer": "^4.11.1",
- "@taiga-ui/cdk": "^4.28.0",
- "@taiga-ui/core": "^4.28.0",
- "@taiga-ui/i18n": "^4.28.0",
- "@taiga-ui/polymorpheus": "^4.8.0",
+ "@taiga-ui/cdk": "^4.30.0",
+ "@taiga-ui/core": "^4.30.0",
+ "@taiga-ui/i18n": "^4.30.0",
+ "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0"
}
},
"node_modules/@taiga-ui/layout": {
- "version": "4.28.0",
- "resolved": "https://registry.npmjs.org/@taiga-ui/layout/-/layout-4.28.0.tgz",
- "integrity": "sha512-NlXdEmXGhYvTWeSSpGlT9XS0SU1aQDuFAMFBSDVsZqLPWh2DTnNsxSf1/b6UYMmX5JKXhH/bRVvX97N5L5XZqQ==",
+ "version": "4.30.0",
+ "resolved": "https://registry.npmjs.org/@taiga-ui/layout/-/layout-4.30.0.tgz",
+ "integrity": "sha512-DyIqpmXcv/OP4byt7L1f1iBKPysf3L+sj/dBpkeYvAUUnJnXnJsXav0j57d43VkXPn9lpGqz0gEBtzVDt7xxTw==",
"license": "Apache-2.0",
"dependencies": {
"tslib": ">=2.8.1"
@@ -4630,17 +4630,17 @@
"peerDependencies": {
"@angular/common": ">=16.0.0",
"@angular/core": ">=16.0.0",
- "@taiga-ui/cdk": "^4.28.0",
- "@taiga-ui/core": "^4.28.0",
- "@taiga-ui/kit": "^4.28.0",
- "@taiga-ui/polymorpheus": "^4.8.0",
+ "@taiga-ui/cdk": "^4.30.0",
+ "@taiga-ui/core": "^4.30.0",
+ "@taiga-ui/kit": "^4.30.0",
+ "@taiga-ui/polymorpheus": "^4.9.0",
"rxjs": ">=7.0.0"
}
},
"node_modules/@taiga-ui/legacy": {
- "version": "4.28.0",
- "resolved": "https://registry.npmjs.org/@taiga-ui/legacy/-/legacy-4.28.0.tgz",
- "integrity": "sha512-mWE5w7alYsT8GMBNTfcvrf/sJjh1li2/mTykH/aoWklgYHHmSt6moY4Myi8wKdlRFBzi82eXsvJcUSCwD8Y5ew==",
+ "version": "4.30.0",
+ "resolved": "https://registry.npmjs.org/@taiga-ui/legacy/-/legacy-4.30.0.tgz",
+ "integrity": "sha512-ebFJMddzlsq3TUAWxopn5Qju4REkC4bHzoYYx5OEzPq1VW1zmCvNC+X6usMnluhc9aS50UI8ZB7Xd3N4Zdgtfg==",
"license": "Apache-2.0",
"dependencies": {
"tslib": ">=2.8.1"
diff --git a/web/package.json b/web/package.json
index 71792c535..f300f6fb2 100644
--- a/web/package.json
+++ b/web/package.json
@@ -47,17 +47,17 @@
"@noble/hashes": "^1.4.0",
"@start9labs/argon2": "^0.2.2",
"@start9labs/start-sdk": "file:../sdk/baseDist",
- "@taiga-ui/addon-charts": "4.28.0",
- "@taiga-ui/addon-commerce": "4.28.0",
- "@taiga-ui/addon-mobile": "4.28.0",
- "@taiga-ui/addon-table": "4.28.0",
- "@taiga-ui/cdk": "4.28.0",
- "@taiga-ui/core": "4.28.0",
- "@taiga-ui/event-plugins": "4.4.1",
- "@taiga-ui/icons": "4.28.0",
- "@taiga-ui/kit": "4.28.0",
- "@taiga-ui/layout": "4.28.0",
- "@taiga-ui/legacy": "4.28.0",
+ "@taiga-ui/addon-charts": "4.30.0",
+ "@taiga-ui/addon-commerce": "4.30.0",
+ "@taiga-ui/addon-mobile": "4.30.0",
+ "@taiga-ui/addon-table": "4.30.0",
+ "@taiga-ui/cdk": "4.30.0",
+ "@taiga-ui/core": "4.30.0",
+ "@taiga-ui/event-plugins": "4.5.0",
+ "@taiga-ui/icons": "4.30.0",
+ "@taiga-ui/kit": "4.30.0",
+ "@taiga-ui/layout": "4.30.0",
+ "@taiga-ui/legacy": "4.30.0",
"@taiga-ui/polymorpheus": "4.9.0",
"@tinkoff/ng-dompurify": "4.0.0",
"ansi-to-html": "^0.7.2",
diff --git a/web/projects/shared/styles/taiga.scss b/web/projects/shared/styles/taiga.scss
index 3edb110f8..68b4b97ca 100644
--- a/web/projects/shared/styles/taiga.scss
+++ b/web/projects/shared/styles/taiga.scss
@@ -162,20 +162,3 @@ tui-badge-notification {
align-self: center !important;
}
}
-
-// TODO Remove after Taiga UI update
-[tuiTitle] {
- h1,
- h2,
- h3,
- h4,
- h5,
- h6 {
- font: inherit;
- margin: 0;
- }
-
- [tuiSubtitle] {
- margin: 0;
- }
-}
diff --git a/web/projects/ui/src/app/i18n/i18n.providers.ts b/web/projects/ui/src/app/i18n/i18n.providers.ts
index 4d44720b9..8239f6edd 100644
--- a/web/projects/ui/src/app/i18n/i18n.providers.ts
+++ b/web/projects/ui/src/app/i18n/i18n.providers.ts
@@ -1,4 +1,4 @@
-import { signal } from '@angular/core'
+import { forwardRef, signal } from '@angular/core'
import { tuiCreateToken, tuiProvide } from '@taiga-ui/cdk'
import {
TuiLanguageName,
@@ -34,5 +34,8 @@ export const I18N_PROVIDERS = [
}
},
},
- tuiProvide(TuiLanguageSwitcherService, i18nService),
+ tuiProvide(
+ TuiLanguageSwitcherService,
+ forwardRef(() => i18nService),
+ ),
]
diff --git a/web/projects/ui/src/app/routes/portal/components/interfaces/actions.component.ts b/web/projects/ui/src/app/routes/portal/components/interfaces/actions.component.ts
index 7f5c97ea7..3c35544b1 100644
--- a/web/projects/ui/src/app/routes/portal/components/interfaces/actions.component.ts
+++ b/web/projects/ui/src/app/routes/portal/components/interfaces/actions.component.ts
@@ -87,9 +87,7 @@ import { InterfaceComponent } from './interface.component'
:host {
text-align: right;
grid-area: 1 / 2 / 3 / 3;
- }
-
- .desktop {
+ place-content: center;
}
.mobile {
diff --git a/web/projects/ui/src/app/routes/portal/components/interfaces/interface.component.ts b/web/projects/ui/src/app/routes/portal/components/interfaces/interface.component.ts
index 1f051808c..42ff76a6f 100644
--- a/web/projects/ui/src/app/routes/portal/components/interfaces/interface.component.ts
+++ b/web/projects/ui/src/app/routes/portal/components/interfaces/interface.component.ts
@@ -19,14 +19,6 @@ import { MappedServiceInterface } from './interface.utils'
flex-direction: column;
gap: 1rem;
}
-
- section {
- padding-block-end: 1rem;
- }
-
- :host-context(tui-root:not(._mobile)) section ::ng-deep > header {
- background: none;
- }
`,
providers: [tuiButtonOptionsProvider({ size: 'xs' })],
changeDetection: ChangeDetectionStrategy.OnPush,
diff --git a/web/projects/ui/src/app/routes/portal/components/table.component.ts b/web/projects/ui/src/app/routes/portal/components/table.component.ts
index 14dc29dd3..d8b5af656 100644
--- a/web/projects/ui/src/app/routes/portal/components/table.component.ts
+++ b/web/projects/ui/src/app/routes/portal/components/table.component.ts
@@ -13,6 +13,11 @@ import { ChangeDetectionStrategy, Component, input } from '@angular/core'
`,
+ styles: `
+ :host:has(app-placeholder) thead {
+ display: none;
+ }
+ `,
host: { class: 'g-table' },
changeDetection: ChangeDetectionStrategy.OnPush,
})
diff --git a/web/projects/ui/src/app/routes/portal/components/tabs.component.ts b/web/projects/ui/src/app/routes/portal/components/tabs.component.ts
index a704d2e32..a34e8f454 100644
--- a/web/projects/ui/src/app/routes/portal/components/tabs.component.ts
+++ b/web/projects/ui/src/app/routes/portal/components/tabs.component.ts
@@ -10,9 +10,7 @@ import { RouterLink, RouterLinkActive } from '@angular/router'
import { TuiResponsiveDialogService, TuiTabBar } from '@taiga-ui/addon-mobile'
import { TuiIcon } from '@taiga-ui/core'
import { TuiBadgeNotification } from '@taiga-ui/kit'
-import { ABOUT } from 'src/app/routes/portal/components/header/about.component'
import { BadgeService } from 'src/app/services/badge.service'
-import { RESOURCES } from 'src/app/utils/resources'
import { getMenu } from 'src/app/utils/system-utilities'
const FILTER = ['/portal/services', '/portal/system', '/portal/marketplace']
@@ -72,20 +70,6 @@ const FILTER = ['/portal/services', '/portal/system', '/portal/marketplace']
}
}
-
-
- About this server
-
- @for (link of resources; track $index) {
-
-
- {{ link.name }}
-
-
- }
@@ -138,7 +122,6 @@ export class TabsComponent {
index = 3
- readonly resources = RESOURCES
readonly menu = getMenu().filter(item => !FILTER.includes(item.routerLink))
readonly badge = toSignal(inject(BadgeService).getCount('/portal/system'), {
initialValue: 0,
@@ -148,10 +131,6 @@ export class TabsComponent {
this.menu.reduce((acc, item) => acc + item.badge(), 0),
)
- about() {
- this.dialogs.open(ABOUT, { label: 'About this server' }).subscribe()
- }
-
more(content: TemplateRef) {
this.dialogs.open(content, { label: 'Start OS' }).subscribe({
complete: () => this.update(),
diff --git a/web/projects/ui/src/app/routes/portal/routes/services/dashboard/dashboard.component.ts b/web/projects/ui/src/app/routes/portal/routes/services/dashboard/dashboard.component.ts
index d2067a72a..c31e74c38 100644
--- a/web/projects/ui/src/app/routes/portal/routes/services/dashboard/dashboard.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/services/dashboard/dashboard.component.ts
@@ -55,6 +55,10 @@ import { ServicesService } from './services.service'
font-size: 1rem;
overflow: hidden;
}
+
+ :host-context(tui-root._mobile) {
+ padding: 0;
+ }
`,
host: { class: 'g-page' },
imports: [ServiceComponent, ToManifestPipe, TuiTable, TitleDirective],
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/acme/acme.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/acme/acme.component.ts
index 46a299738..864a8a33b 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/acme/acme.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/acme/acme.component.ts
@@ -2,8 +2,8 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import { ErrorService, LoadingService } from '@start9labs/shared'
import { ISB, utils } from '@start9labs/start-sdk'
-import { TuiButton, TuiLoader, TuiTitle } from '@taiga-ui/core'
-import { TuiCell } from '@taiga-ui/layout'
+import { TuiButton, TuiLink, TuiLoader, TuiTitle } from '@taiga-ui/core'
+import { TuiCell, TuiHeader } from '@taiga-ui/layout'
import { PatchDB } from 'patch-db-client'
import { map } from 'rxjs'
import { FormComponent } from 'src/app/routes/portal/components/form.component'
@@ -12,11 +12,28 @@ import { FormDialogService } from 'src/app/services/form-dialog.service'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { knownACME, toAcmeName } from 'src/app/utils/acme'
import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec'
-import { AcmeInfoComponent } from './info.component'
@Component({
template: `
-
+
Saved Providers
@@ -62,9 +79,14 @@ import { AcmeInfoComponent } from './info.component'
}
`,
+ styles: `
+ :host {
+ max-width: 40rem;
+ }
+ `,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
- imports: [TuiButton, TuiLoader, TuiCell, TuiTitle, AcmeInfoComponent],
+ imports: [TuiButton, TuiLoader, TuiCell, TuiTitle, TuiHeader, TuiLink],
})
export default class SystemAcmeComponent {
private readonly formDialog = inject(FormDialogService)
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/acme/info.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/acme/info.component.ts
deleted file mode 100644
index 74047f79a..000000000
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/acme/info.component.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { ChangeDetectionStrategy, Component } from '@angular/core'
-import { TuiLink, TuiNotification } from '@taiga-ui/core'
-
-@Component({
- selector: 'acme-info',
- template: `
-
- Register with one or more ACME providers such as Let's Encrypt in order to
- generate SSL (https) certificates on-demand for clearnet hosting.
-
-
- `,
- changeDetection: ChangeDetectionStrategy.OnPush,
- standalone: true,
- imports: [TuiNotification, TuiLink],
-})
-export class AcmeInfoComponent {}
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/backups.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/backups.component.ts
index 267bb08c8..e095d7947 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/backups.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/backups.component.ts
@@ -1,21 +1,32 @@
-import { AsyncPipe } from '@angular/common'
+import { AsyncPipe, DatePipe } from '@angular/common'
import {
ChangeDetectionStrategy,
Component,
inject,
OnInit,
} from '@angular/core'
+import { toSignal } from '@angular/core/rxjs-interop'
import { ActivatedRoute, RouterLink } from '@angular/router'
import { UnitConversionPipesModule } from '@start9labs/shared'
import { TuiResponsiveDialogService } from '@taiga-ui/addon-mobile'
-import { TuiButton, TuiLink, TuiLoader } from '@taiga-ui/core'
-import { BACKUP } from 'src/app/routes/portal/routes/system/routes/backups/backup.component'
+import { TuiMapperPipe } from '@taiga-ui/cdk'
+import {
+ TuiButton,
+ TuiLink,
+ TuiLoader,
+ TuiNotification,
+ TuiTitle,
+} from '@taiga-ui/core'
+import { TuiHeader } from '@taiga-ui/layout'
+import { PatchDB } from 'patch-db-client'
import {
CifsBackupTarget,
DiskBackupTarget,
} from 'src/app/services/api/api.types'
import { EOSService } from 'src/app/services/eos.service'
+import { DataModel } from 'src/app/services/patch-db/data-model'
import { TitleDirective } from 'src/app/services/title.service'
+import { BACKUP } from './backup.component'
import { BackupService, MappedBackupTarget } from './backup.service'
import { BackupNetworkComponent } from './network.component'
import { BackupPhysicalComponent } from './physical.component'
@@ -29,6 +40,53 @@ import { BACKUP_RESTORE } from './restore.component'
{{ type === 'create' ? 'Create Backup' : 'Restore Backup' }}
+
+
+ @if (type === 'create' && server(); as s) {
+
+
+ Last Backup
+
+ {{ s.lastBackup ? (s.lastBackup | date: 'medium') : 'never' }}
+
+
+
+ }
+
@if (type === 'create' && (eos.backingUp$ | async)) {
} @else {
@@ -40,8 +98,7 @@ import { BACKUP_RESTORE } from './restore.component'
/>
} @else {
- {{ text }}
- a folder on another computer that is connected to the same network as
+ A folder on another computer that is connected to the same network as
your Start9 server. View the
- {{ text }}
- a physical drive that is plugged directly into your Start9 Server.
- View the
-
+ A physical drive that is plugged directly into your Start9 Server.
}
}
@@ -71,15 +118,20 @@ import { BACKUP_RESTORE } from './restore.component'
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
+ AsyncPipe,
+ DatePipe,
RouterLink,
TuiButton,
TuiLoader,
TuiLink,
+ TuiHeader,
+ TuiTitle,
+ TuiNotification,
+ TuiMapperPipe,
TitleDirective,
UnitConversionPipesModule,
BackupNetworkComponent,
BackupPhysicalComponent,
- AsyncPipe,
BackupProgressComponent,
],
})
@@ -88,11 +140,25 @@ export default class SystemBackupComponent implements OnInit {
readonly type = inject(ActivatedRoute).snapshot.data['type']
readonly service = inject(BackupService)
readonly eos = inject(EOSService)
+ readonly server = toSignal(
+ inject>(PatchDB).watch$('serverInfo'),
+ )
- get text() {
- return this.type === 'create'
- ? 'Backup server to'
- : 'Restore your services from'
+ readonly toAppearance = (lastBackup: string | null) => {
+ if (!lastBackup) return 'negative'
+
+ const currentDate = new Date().valueOf()
+ const backupDate = new Date(lastBackup).valueOf()
+ const diff = currentDate - backupDate
+ const week = 604800000
+
+ if (diff <= week) {
+ return 'positive'
+ } else if (diff > week && diff <= week * 2) {
+ return 'warning'
+ } else {
+ return 'negative'
+ }
}
ngOnInit() {
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/network.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/network.component.ts
index 8eb06bbf8..850fef900 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/network.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/network.component.ts
@@ -14,6 +14,7 @@ import { TuiCell } from '@taiga-ui/layout'
import { filter } from 'rxjs'
import { FormComponent } from 'src/app/routes/portal/components/form.component'
import { PlaceholderComponent } from 'src/app/routes/portal/components/placeholder.component'
+import { TableComponent } from 'src/app/routes/portal/components/table.component'
import { CifsBackupTarget, RR } from 'src/app/services/api/api.types'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { FormDialogService } from 'src/app/services/form-dialog.service'
@@ -37,69 +38,132 @@ const ERROR =
- @for (target of service.cifs(); track $index) {
-
-
-
- {{ target.entry.path.split('/').pop() }}
- @if (target.entry.mountable) {
-
- } @else {
-
-
- Unable to connect
-
- }
-
- Hostname:
- {{ target.entry.hostname }}
-
-
- Path:
- {{ target.entry.path }}
-
-
-
+ @for (target of service.cifs(); track $index) {
+
- Forget
-
-
- Edit
-
-
- } @empty {
- No network folders
- }
+
+ @if (target.entry.mountable) {
+
+ } @else {
+
+
+ Unable to connect
+
+ }
+
+ {{ target.entry.path.split('/').pop() }}
+ {{ target.entry.hostname }}
+ {{ target.entry.path }}
+
+
+ Forget
+
+
+ Edit
+
+
+
+ } @empty {
+
+
+
+ No network folders
+
+
+
+ }
+
`,
styles: `
+ @import '@taiga-ui/core/styles/taiga-ui-local';
+
+ tr {
+ cursor: pointer;
+ @include transition(background);
+
+ @media ($tui-mouse) {
+ &:hover {
+ background: var(--tui-background-neutral-1-hover);
+ }
+ }
+ }
+
+ td:first-child {
+ width: 13rem;
+ }
+
[tuiButton] {
margin-inline-start: auto;
}
+
+ span {
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+ }
+
+ :host-context(tui-root._mobile) {
+ tr {
+ grid-template-columns: min-content 1fr 4rem;
+ white-space: nowrap;
+ }
+
+ td {
+ grid-column: span 2;
+
+ &:first-child {
+ font-size: 0;
+ width: auto;
+ grid-area: 1 / 2;
+ place-content: center;
+ margin: 0 0.5rem;
+ }
+
+ &:last-child {
+ grid-area: 1 / 3 / 4 / 3;
+ align-self: center;
+ justify-self: end;
+ }
+ }
+
+ .name {
+ color: var(--tui-text-primary);
+ font: var(--tui-font-text-m);
+ font-weight: bold;
+ grid-column: 1;
+ max-width: 12rem;
+ }
+ }
`,
host: { class: 'g-card' },
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
TuiButton,
- TuiCell,
TuiIcon,
- TuiTitle,
TuiTooltip,
PlaceholderComponent,
BackupStatusComponent,
+ TableComponent,
],
})
export class BackupNetworkComponent {
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/physical.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/physical.component.ts
index 46c78ec2b..86a1424f4 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/physical.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/physical.component.ts
@@ -6,16 +6,10 @@ import {
} from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { UnitConversionPipesModule } from '@start9labs/shared'
-import {
- TuiAlertService,
- TuiButton,
- TuiIcon,
- TuiNotification,
- TuiTitle,
-} from '@taiga-ui/core'
+import { TuiAlertService, TuiButton, TuiIcon } from '@taiga-ui/core'
import { TuiTooltip } from '@taiga-ui/kit'
-import { TuiCell } from '@taiga-ui/layout'
import { PlaceholderComponent } from 'src/app/routes/portal/components/placeholder.component'
+import { TableComponent } from 'src/app/routes/portal/components/table.component'
import { DiskBackupTarget } from 'src/app/services/api/api.types'
import { BackupService, MappedBackupTarget } from './backup.service'
import { BackupStatusComponent } from './status.component'
@@ -30,58 +24,97 @@ import { BackupStatusComponent } from './status.component'
-
- Warning. Do not use this option if you are using a Raspberry Pi with an
- external SSD. The Raspberry Pi does not support more than one external
- drive without additional power and can cause data corruption.
-
-
- @for (target of service.drives(); track $index) {
-
-
-
- {{ target.entry.label || target.entry.logicalname }}
-
-
+
+ @for (target of service.drives(); track $index) {
+
+
+
+ {{ target.entry.label || target.entry.logicalname }}
+
+
{{ target.entry.vendor || 'Unknown Vendor' }} -
{{ target.entry.model || 'Unknown Model' }}
-
-
- Capacity:
- {{ target.entry.capacity | convertBytes }}
-
-
-
- } @empty {
-
- No drives detected
-
- Refresh
-
-
- }
+
+ {{ target.entry.capacity | convertBytes }}
+
+ } @empty {
+
+
+
+ No drives detected
+
+ Refresh
+
+
+
+
+ }
+
`,
styles: `
- tui-notification {
- margin: 0.5rem 0 0.75rem;
+ @import '@taiga-ui/core/styles/taiga-ui-local';
+
+ tr {
+ cursor: pointer;
+ @include transition(background);
+
+ @media ($tui-mouse) {
+ &:hover {
+ background: var(--tui-background-neutral-1-hover);
+ }
+ }
+ }
+
+ td:first-child {
+ width: 13rem;
+ }
+
+ :host-context(tui-root._mobile) {
+ tr {
+ max-width: 18rem;
+ grid-template-columns: min-content 2rem;
+ white-space: nowrap;
+ }
+
+ td {
+ grid-column: span 2;
+
+ &:first-child {
+ font-size: 0;
+ width: auto;
+ grid-area: 1 / 2;
+ place-content: center;
+ margin: 0 0.5rem;
+ }
+ }
+
+ .name {
+ color: var(--tui-text-primary);
+ font: var(--tui-font-text-m);
+ font-weight: bold;
+ grid-column: 1;
+ max-width: 12rem;
+ }
}
`,
host: { class: 'g-card' },
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
TuiButton,
- TuiCell,
TuiIcon,
- TuiTitle,
TuiTooltip,
- TuiNotification,
UnitConversionPipesModule,
PlaceholderComponent,
BackupStatusComponent,
+ TableComponent,
],
})
export class BackupPhysicalComponent {
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/status.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/status.component.ts
index 5be91ff76..2a83f5530 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/status.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/backups/status.component.ts
@@ -26,12 +26,19 @@ import { TuiIcon } from '@taiga-ui/core'
`,
styles: `
:host {
- color: var(--tui-text-primary);
+ height: 2rem;
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
}
tui-icon {
font-size: 1rem;
}
+
+ :host-context(tui-root._mobile) {
+ height: auto;
+ }
`,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [TuiIcon],
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/email/email.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/email/email.component.ts
index 8599ce43a..53aa66425 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/email/email.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/email/email.component.ts
@@ -3,8 +3,9 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
import { RouterLink } from '@angular/router'
import { ErrorService, LoadingService } from '@start9labs/shared'
-import { IST, inputSpec } from '@start9labs/start-sdk'
-import { TuiButton, TuiDialogService } from '@taiga-ui/core'
+import { inputSpec, IST } from '@start9labs/start-sdk'
+import { TuiButton, TuiDialogService, TuiLink, TuiTitle } from '@taiga-ui/core'
+import { TuiHeader } from '@taiga-ui/layout'
import { TuiInputModule } from '@taiga-ui/legacy'
import { PatchDB } from 'patch-db-client'
import { switchMap, tap } from 'rxjs'
@@ -14,7 +15,6 @@ import { FormService } from 'src/app/services/form.service'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { TitleDirective } from 'src/app/services/title.service'
import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec'
-import { EmailInfoComponent } from './info.component'
@Component({
template: `
@@ -22,18 +22,38 @@ import { EmailInfoComponent } from './info.component'
Back
Email
-
-
-
-
-
+ }
`,
styles: `
:host {
- display: grid !important;
- grid-template-columns: 1fr 1fr;
- align-items: start;
+ max-width: 40rem;
}
- :host-context(tui-root._mobile) {
- grid-template-columns: 1fr;
+ form header,
+ form footer {
+ margin: 1rem 0;
+ display: flex;
+ gap: 1rem;
+ }
+
+ footer {
+ justify-content: flex-end;
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -91,7 +120,9 @@ import { EmailInfoComponent } from './info.component'
FormModule,
TuiButton,
TuiInputModule,
- EmailInfoComponent,
+ TuiHeader,
+ TuiTitle,
+ TuiLink,
RouterLink,
TitleDirective,
],
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/email/info.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/email/info.component.ts
deleted file mode 100644
index f1bd31420..000000000
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/email/info.component.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-import { ChangeDetectionStrategy, Component } from '@angular/core'
-import { TuiLink, TuiNotification } from '@taiga-ui/core'
-
-@Component({
- selector: 'email-info',
- template: `
-
- Adding SMTP credentials to StartOS enables StartOS and some services to
- send you emails.
-
-
- `,
- styles: `
- :host {
- grid-column: span 2;
- }
-
- :host-context(tui-root._mobile) {
- grid-column: 1;
- }
- `,
- changeDetection: ChangeDetectionStrategy.OnPush,
- standalone: true,
- imports: [TuiNotification, TuiLink],
-})
-export class EmailInfoComponent {}
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/interfaces/interfaces.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/interfaces/interfaces.component.ts
index fc288c6bd..31bb6727e 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/interfaces/interfaces.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/interfaces/interfaces.component.ts
@@ -2,7 +2,8 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import { RouterLink } from '@angular/router'
import { T } from '@start9labs/start-sdk'
-import { TuiButton } from '@taiga-ui/core'
+import { TuiButton, TuiTitle } from '@taiga-ui/core'
+import { TuiHeader } from '@taiga-ui/layout'
import { PatchDB } from 'patch-db-client'
import { map } from 'rxjs'
import { InterfaceComponent } from 'src/app/routes/portal/components/interfaces/interface.component'
@@ -34,13 +35,29 @@ const iface: T.ServiceInterface = {
Back
Web Addresses
+
@if (ui(); as ui) {
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
- imports: [InterfaceComponent, RouterLink, TuiButton, TitleDirective],
+ imports: [
+ InterfaceComponent,
+ RouterLink,
+ TuiButton,
+ TitleDirective,
+ TuiHeader,
+ TuiTitle,
+ ],
})
export default class StartOsUiComponent {
private readonly config = inject(ConfigService)
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/password/password.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/password/password.component.ts
index 388d4a586..216f0891d 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/password/password.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/password/password.component.ts
@@ -10,6 +10,7 @@ import {
TuiNotification,
TuiTitle,
} from '@taiga-ui/core'
+import { TuiHeader } from '@taiga-ui/layout'
import { PatchDB } from 'patch-db-client'
import { from } from 'rxjs'
import { FormComponent } from 'src/app/routes/portal/components/form.component'
@@ -23,22 +24,23 @@ import { getServerInfo } from 'src/app/utils/get-server-info'
template: `
Back
- Password Reset
+ Change Password
-
-
-
Warning
-
- You will still need your current password to decrypt existing backups!
-
-
-
-
-
- @if (spec(); as spec) {
-
- }
-
+
+ @if (spec(); as spec) {
+
+ }
`,
styles: `
:host {
@@ -46,6 +48,7 @@ import { getServerInfo } from 'src/app/utils/get-server-info'
::ng-deep footer {
background: transparent !important;
+ margin: 0;
}
}
@@ -56,11 +59,11 @@ import { getServerInfo } from 'src/app/utils/get-server-info'
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
- TuiNotification,
- TuiTitle,
- FormComponent,
RouterLink,
+ TuiHeader,
+ TuiTitle,
TuiButton,
+ FormComponent,
TitleDirective,
],
})
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/sessions.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/sessions.component.ts
index 55de658e6..10f93fc88 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/sessions.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/sessions.component.ts
@@ -1,10 +1,11 @@
import { RouterLink } from '@angular/router'
import { TuiTable } from '@taiga-ui/addon-table'
import { TuiLet } from '@taiga-ui/cdk'
-import { TuiButton } from '@taiga-ui/core'
+import { TuiButton, TuiTitle } from '@taiga-ui/core'
import { CommonModule } from '@angular/common'
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { ErrorService, LoadingService } from '@start9labs/shared'
+import { TuiHeader } from '@taiga-ui/layout'
import { from, map, merge, Observable, Subject } from 'rxjs'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { Session } from 'src/app/services/api/api.types'
@@ -17,14 +18,18 @@ import { SSHTableComponent } from './table.component'
Back
Active Sessions
+
@@ -43,7 +48,7 @@ import { SSHTableComponent } from './table.component'
}
-
+
`,
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -56,6 +61,8 @@ import { SSHTableComponent } from './table.component'
RouterLink,
TitleDirective,
TuiTable,
+ TuiHeader,
+ TuiTitle,
],
})
export default class SystemSessionsComponent {
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/table.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/table.component.ts
index f6ab49941..18617f4e7 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/table.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/sessions/table.component.ts
@@ -6,53 +6,32 @@ import {
OnChanges,
} from '@angular/core'
import { FormsModule } from '@angular/forms'
-import { TuiTable } from '@taiga-ui/addon-table'
import { TuiIcon } from '@taiga-ui/core'
import { TuiCheckbox, TuiFade, TuiSkeleton } from '@taiga-ui/kit'
import { BehaviorSubject } from 'rxjs'
+import { TableComponent } from 'src/app/routes/portal/components/table.component'
import { Session } from 'src/app/services/api/api.types'
import { PlatformInfoPipe } from './platform-info.pipe'
@Component({
- selector: 'table[sessions]',
+ selector: '[sessions]',
template: `
-
-
-
- @if (!single) {
-
- }
- User Agent
-
- Platform
- Last Active
-
-
-
+
`,
styles: [
`
@@ -81,16 +60,37 @@ import { PlatformInfoPipe } from './platform-info.pipe'
td {
position: relative;
+ width: 25%;
+
+ &[colspan] {
+ grid-column: span 2;
+ }
+
+ &:first-child {
+ width: 50%;
+ }
}
input {
position: absolute;
top: 50%;
- left: 0.5rem;
+ left: 0.75rem;
transform: translateY(-50%);
}
+ .platform {
+ white-space: nowrap;
+ }
+
:host-context(tui-root._mobile) {
+ tr {
+ grid-template-columns: 2.5rem 1fr;
+
+ &:has(:checked) .platform {
+ color: var(--tui-text-action);
+ }
+ }
+
input {
@include fullsize();
z-index: 1;
@@ -98,8 +98,12 @@ import { PlatformInfoPipe } from './platform-info.pipe'
transform: none;
}
- td:first-child {
- padding: 0 0.25rem !important;
+ td {
+ width: 100%;
+
+ &:first-child {
+ padding: 0 !important;
+ }
}
.agent {
@@ -108,11 +112,9 @@ import { PlatformInfoPipe } from './platform-info.pipe'
}
.platform {
- font-weight: bold;
- display: flex;
- align-items: center;
- gap: 0.5rem;
- padding: 0;
+ font-size: 0;
+ grid-area: 1 / 1 / 3 / 1;
+ place-content: center;
}
.date {
@@ -131,7 +133,7 @@ import { PlatformInfoPipe } from './platform-info.pipe'
TuiCheckbox,
TuiFade,
TuiSkeleton,
- TuiTable,
+ TableComponent,
],
})
export class SSHTableComponent implements OnChanges {
@@ -143,26 +145,10 @@ export class SSHTableComponent implements OnChanges {
@Input()
single = false
- get all(): boolean | null {
- if (!this.sessions?.length || !this.selected$.value.length) {
- return false
- }
-
- if (this.sessions?.length === this.selected$.value.length) {
- return true
- }
-
- return null
- }
-
ngOnChanges() {
this.selected$.next([])
}
- onAll(selected: boolean) {
- this.selected$.next((selected && this.sessions) || [])
- }
-
onToggle(session: T) {
const selected = this.selected$.value
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/info.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/info.component.ts
deleted file mode 100644
index f68231cf2..000000000
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/info.component.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { ChangeDetectionStrategy, Component } from '@angular/core'
-import { TuiLink, TuiNotification } from '@taiga-ui/core'
-
-@Component({
- selector: 'ssh-info',
- template: `
-
- Adding domains to StartOS enables you to access your server and service
- interfaces over clearnet.
-
- View instructions
-
-
- `,
- changeDetection: ChangeDetectionStrategy.OnPush,
- standalone: true,
- imports: [TuiNotification, TuiLink],
-})
-export class SSHInfoComponent {}
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/ssh.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/ssh.component.ts
index da9c30072..5d2e4e832 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/ssh.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/ssh.component.ts
@@ -1,13 +1,13 @@
import { RouterLink } from '@angular/router'
import { TuiTable } from '@taiga-ui/addon-table'
-import { TuiButton } from '@taiga-ui/core'
+import { TuiButton, TuiLink, TuiTitle } from '@taiga-ui/core'
import { CommonModule } from '@angular/common'
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { ErrorService } from '@start9labs/shared'
+import { TuiHeader } from '@taiga-ui/layout'
import { catchError, defer, of } from 'rxjs'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { TitleDirective } from 'src/app/services/title.service'
-import { SSHInfoComponent } from './info.component'
import { SSHTableComponent } from './table.component'
@Component({
@@ -16,7 +16,24 @@ import { SSHTableComponent } from './table.component'
Back
SSH
-
+
Saved Keys
@@ -30,7 +47,7 @@ import { SSHTableComponent } from './table.component'
Add Key
-
+
`,
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -39,10 +56,12 @@ import { SSHTableComponent } from './table.component'
CommonModule,
TuiButton,
SSHTableComponent,
- SSHInfoComponent,
RouterLink,
TitleDirective,
TuiTable,
+ TuiHeader,
+ TuiTitle,
+ TuiLink,
],
})
export default class SystemSSHComponent {
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/table.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/table.component.ts
index 496be4fb2..5124ae8da 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/table.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/ssh/table.component.ts
@@ -7,32 +7,25 @@ import {
Input,
} from '@angular/core'
import { ErrorService, LoadingService } from '@start9labs/shared'
-import { TuiTable } from '@taiga-ui/addon-table'
-import { TuiDialogOptions, TuiDialogService, TuiButton } from '@taiga-ui/core'
+import { TuiButton, TuiDialogOptions, TuiDialogService } from '@taiga-ui/core'
import {
+ TUI_CONFIRM,
TuiConfirmData,
TuiFade,
- TUI_CONFIRM,
TuiSkeleton,
} from '@taiga-ui/kit'
import { filter, take } from 'rxjs'
+import { TableComponent } from 'src/app/routes/portal/components/table.component'
import { PROMPT } from 'src/app/routes/portal/modals/prompt.component'
import { SSHKey } from 'src/app/services/api/api.types'
import { ApiService } from 'src/app/services/api/embassy-api.service'
@Component({
- selector: 'table[keys]',
+ selector: '[keys]',
template: `
-
-
- Hostname
- Created At
- Algorithm
- Fingerprint
-
-
-
-
+
@for (key of keys; track $index) {
{{ key.hostname }}
@@ -62,7 +55,7 @@ import { ApiService } from 'src/app/services/api/embassy-api.service'
}
}
}
-
+
`,
styles: `
:host-context(tui-root._mobile) {
@@ -109,7 +102,7 @@ import { ApiService } from 'src/app/services/api/embassy-api.service'
`,
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
- imports: [CommonModule, TuiButton, TuiFade, TuiSkeleton, TuiTable],
+ imports: [CommonModule, TuiButton, TuiFade, TuiSkeleton, TableComponent],
})
export class SSHTableComponent {
private readonly loader = inject(LoadingService)
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/info.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/info.component.ts
deleted file mode 100644
index 55fdac670..000000000
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/info.component.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { ChangeDetectionStrategy, Component } from '@angular/core'
-import { TuiLink, TuiNotification } from '@taiga-ui/core'
-
-@Component({
- selector: 'wifi-info',
- template: `
-
- Adding WiFi credentials to StartOS allows you to remove the Ethernet cable
- and move the device anywhere you want. StartOS will automatically connect
- to available networks.
-
-
- `,
- changeDetection: ChangeDetectionStrategy.OnPush,
- standalone: true,
- imports: [TuiNotification, TuiLink],
-})
-export class WifiInfoComponent {}
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/table.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/table.component.ts
index 4b759ac9e..a907027bd 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/table.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/table.component.ts
@@ -24,27 +24,26 @@ import SystemWifiComponent from './wifi.component'
template: `
@for (network of wifi; track $index) {
@if (network.ssid) {
-
+
{{ network.ssid }}
@if (network.connected) {
- Connected
+ Connected
}
- @if (!network.connected) {
-
- Connect
-
- }
@if (network.connected !== undefined) {
Forget
@@ -63,14 +62,22 @@ import SystemWifiComponent from './wifi.component'
} @else {
}
-
+
}
}
`,
styles: `
:host {
align-items: stretch;
- white-space: nowrap;
+ padding: 0.5rem !important;
+ }
+
+ [tuiCell] {
+ padding-inline: 1rem !important;
+
+ &:disabled > * {
+ opacity: 1;
+ }
}
tui-icon {
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/wifi.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/wifi.component.ts
index f4fadffed..59545a616 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/wifi.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/wifi/wifi.component.ts
@@ -13,10 +13,12 @@ import {
TuiAppearance,
TuiButton,
TuiDialogOptions,
+ TuiLink,
TuiLoader,
+ TuiTitle,
} from '@taiga-ui/core'
import { TuiSwitch } from '@taiga-ui/kit'
-import { TuiCardLarge } from '@taiga-ui/layout'
+import { TuiCardLarge, TuiHeader } from '@taiga-ui/layout'
import { PatchDB } from 'patch-db-client'
import { catchError, defer, map, merge, Observable, of, Subject } from 'rxjs'
import {
@@ -28,7 +30,6 @@ import { ApiService } from 'src/app/services/api/embassy-api.service'
import { FormDialogService } from 'src/app/services/form-dialog.service'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { TitleDirective } from 'src/app/services/title.service'
-import { WifiInfoComponent } from './info.component'
import { WifiTableComponent } from './table.component'
import { parseWifi, WifiData, WiFiForm } from './utils'
import { wifiSpec } from './wifi.const'
@@ -39,7 +40,26 @@ import { wifiSpec } from './wifi.const'
Back
WiFi
-
+
@if (status()?.interface) {
@@ -60,7 +80,6 @@ import { wifiSpec } from './wifi.const'
tuiCardLarge="compact"
tuiAppearance="neutral"
[wifi]="data.known"
- [style.padding-block.rem]="0.5"
>
}
@if (data.available.length) {
@@ -69,11 +88,10 @@ import { wifiSpec } from './wifi.const'
tuiCardLarge="compact"
tuiAppearance="neutral"
[wifi]="data.available"
- [style.padding-block.rem]="0.5"
>
}
- Add
+ Add
} @else {
@@ -88,6 +106,11 @@ import { wifiSpec } from './wifi.const'
}
`,
+ styles: `
+ :host {
+ max-width: 40rem;
+ }
+ `,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
@@ -97,11 +120,13 @@ import { wifiSpec } from './wifi.const'
TuiCardLarge,
TuiLoader,
TuiAppearance,
- WifiInfoComponent,
WifiTableComponent,
TitleDirective,
RouterLink,
PlaceholderComponent,
+ TuiHeader,
+ TuiTitle,
+ TuiLink,
],
})
export default class SystemWifiComponent {
diff --git a/web/projects/ui/src/app/routes/portal/routes/system/system.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/system.component.ts
index c73cc768f..0e3e6c01e 100644
--- a/web/projects/ui/src/app/routes/portal/routes/system/system.component.ts
+++ b/web/projects/ui/src/app/routes/portal/routes/system/system.component.ts
@@ -11,7 +11,7 @@ import { SYSTEM_MENU } from './system.const'
@Component({
template: `
- {{ 'system.outlet.general' | i18n }}
+ {{ 'system.outlet.system' | i18n }}
@for (cat of menu; track $index) {
@if ($index) {
@@ -45,6 +45,10 @@ import { SYSTEM_MENU } from './system.const'
padding: 0;
}
+ tui-badge-notification {
+ vertical-align: baseline;
+ }
+
[tuiCell] {
color: var(--tui-text-secondary);
@@ -94,6 +98,10 @@ import { SYSTEM_MENU } from './system.const'
hr {
background: var(--tui-border-normal);
}
+
+ ::ng-deep hgroup h3 {
+ display: none;
+ }
}
`,
],
diff --git a/web/projects/ui/src/app/utils/system-utilities.ts b/web/projects/ui/src/app/utils/system-utilities.ts
index 7956395cb..13abd4003 100644
--- a/web/projects/ui/src/app/utils/system-utilities.ts
+++ b/web/projects/ui/src/app/utils/system-utilities.ts
@@ -16,6 +16,7 @@ export const SYSTEM_UTILITIES: Record =
icon: '@tui.upload',
title: 'Sideload',
},
+ // @TODO 040
// '/portal/updates': {
// icon: '@tui.globe',
// title: 'Updates',
diff --git a/web/projects/ui/src/styles.scss b/web/projects/ui/src/styles.scss
index cddfdfffe..62ebb31b9 100644
--- a/web/projects/ui/src/styles.scss
+++ b/web/projects/ui/src/styles.scss
@@ -121,6 +121,14 @@ hr {
padding-top: 4rem;
}
+ tui-root:not(._mobile) &:has(.g-table:not([tuiTable])) {
+ padding-block-end: 1rem;
+
+ > header {
+ background: none;
+ }
+ }
+
[tuiCell] {
margin: 0 -0.625rem;
border-radius: var(--tui-radius-s);
@@ -179,7 +187,6 @@ hr {
th {
position: relative;
font: var(--tui-font-text-s);
- height: 2rem;
padding: 0.5rem 0.75rem;
border: 1px solid var(--tui-background-neutral-1);
border-left: 0;
@@ -193,6 +200,11 @@ hr {
text-align: left;
}
+ tr:focus-visible {
+ outline: none;
+ box-shadow: inset 0 0 0 0.125rem var(--tui-border-focus);
+ }
+
tui-root._mobile & {
min-width: 0;
border: none;
@@ -215,10 +227,6 @@ hr {
}
}
- tr:has(:checked) {
- box-shadow: inset 0 0 0 0.125rem var(--tui-background-accent-1);
- }
-
td,
th {
position: static;