From 32999fc55ff50215f0cc9a0c13fccc03f37a4605 Mon Sep 17 00:00:00 2001 From: waterplea Date: Mon, 4 Aug 2025 19:34:57 +0700 Subject: [PATCH] refactor: domains page --- web/package-lock.json | 200 +++++++------- web/package.json | 22 +- .../shared/src/i18n/dictionaries/de.ts | 3 + .../shared/src/i18n/dictionaries/en.ts | 3 + .../shared/src/i18n/dictionaries/es.ts | 3 + .../shared/src/i18n/dictionaries/fr.ts | 3 + .../shared/src/i18n/dictionaries/pl.ts | 3 + .../shared/src/services/dialog.service.ts | 6 +- .../portal/components/table.component.ts | 2 +- .../system/routes/domains/acme.component.ts | 87 +++++++ .../system/routes/domains/acme.service.ts | 163 ++++++++++++ .../system/routes/domains/domain.component.ts | 134 ++++++++++ .../routes/domains/domains.component.ts | 244 +++--------------- .../system/routes/domains/item.component.ts | 102 -------- .../system/routes/domains/table.component.ts | 128 +++------ .../portal/routes/system/system.const.ts | 10 +- 16 files changed, 591 insertions(+), 522 deletions(-) create mode 100644 web/projects/ui/src/app/routes/portal/routes/system/routes/domains/acme.component.ts create mode 100644 web/projects/ui/src/app/routes/portal/routes/system/routes/domains/acme.service.ts create mode 100644 web/projects/ui/src/app/routes/portal/routes/system/routes/domains/domain.component.ts delete mode 100644 web/projects/ui/src/app/routes/portal/routes/system/routes/domains/item.component.ts diff --git a/web/package-lock.json b/web/package-lock.json index 3e4bb536a..8cfdd9e05 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -25,19 +25,19 @@ "@noble/hashes": "^1.4.0", "@start9labs/argon2": "^0.3.0", "@start9labs/start-sdk": "file:../sdk/baseDist", - "@taiga-ui/addon-charts": "4.44.0", - "@taiga-ui/addon-commerce": "4.44.0", - "@taiga-ui/addon-mobile": "4.44.0", - "@taiga-ui/addon-table": "4.44.0", - "@taiga-ui/cdk": "4.44.0", - "@taiga-ui/core": "4.44.0", + "@taiga-ui/addon-charts": "4.47.0", + "@taiga-ui/addon-commerce": "4.47.0", + "@taiga-ui/addon-mobile": "4.47.0", + "@taiga-ui/addon-table": "4.47.0", + "@taiga-ui/cdk": "4.47.0", + "@taiga-ui/core": "4.47.0", "@taiga-ui/dompurify": "4.1.11", "@taiga-ui/event-plugins": "4.6.0", - "@taiga-ui/experimental": "4.44.0", - "@taiga-ui/icons": "4.44.0", - "@taiga-ui/kit": "4.44.0", - "@taiga-ui/layout": "4.44.0", - "@taiga-ui/legacy": "4.44.0", + "@taiga-ui/experimental": "4.47.0", + "@taiga-ui/icons": "4.47.0", + "@taiga-ui/kit": "4.47.0", + "@taiga-ui/layout": "4.47.0", + "@taiga-ui/legacy": "4.47.0", "@taiga-ui/polymorpheus": "4.9.0", "ansi-to-html": "^0.7.2", "base64-js": "^1.5.1", @@ -2978,9 +2978,9 @@ ] }, "node_modules/@maskito/angular": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/@maskito/angular/-/angular-3.10.0.tgz", - "integrity": "sha512-5WwzV12MLJoCUD4ROEafUmyrElzGesWI4BqAFkh9jzzQRtrF1QNomK9tOVBXmXUBWb5sohiiNViAvRCtGdyXiA==", + "version": "3.10.2", + "resolved": "https://registry.npmjs.org/@maskito/angular/-/angular-3.10.2.tgz", + "integrity": "sha512-+CQ7KQGmu35THj/59Uex+GotMFzdLHFUlPj5X5qphl+tHX09atmRzx7SEUCSEErbftTLafAFeR5N5t1fVTJvmw==", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -2989,35 +2989,35 @@ "peerDependencies": { "@angular/core": ">=16.0.0", "@angular/forms": ">=16.0.0", - "@maskito/core": "^3.10.0" + "@maskito/core": "^3.10.2" } }, "node_modules/@maskito/core": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/@maskito/core/-/core-3.10.0.tgz", - "integrity": "sha512-T3PaMb4ipMmN9hkaAj8uyN0Mqj8XcXMZ1GRZ2WfZePRPHoi/L3tEEEh7vjg1m4TpI3lReRkNQs9yaPZV9ce8HA==", + "version": "3.10.2", + "resolved": "https://registry.npmjs.org/@maskito/core/-/core-3.10.2.tgz", + "integrity": "sha512-LKh/PrG5wtMQ4AFYrWkKVGJUQB2CJcIt59qMPhntYIBpjw/OHWboHD4WWWQ94GvkYKjKQyjMcS/zvx+JaDrx2A==", "license": "Apache-2.0", "peer": true }, "node_modules/@maskito/kit": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/@maskito/kit/-/kit-3.10.0.tgz", - "integrity": "sha512-b/aN200U0w/tNfLPRiXJaHGZRNVimq7UnhjKYoLXejX1+pKKhQ6S/dVg9k0+30IXdmUJ5Uk29y5X3UBc5d1w8A==", + "version": "3.10.2", + "resolved": "https://registry.npmjs.org/@maskito/kit/-/kit-3.10.2.tgz", + "integrity": "sha512-d0YHheVt+DYZDL+A4uwoF0pF/rofczHz0KKYEuQrSdbKlRxOdyckQrj9iMCsmD73Hwne7LbjLL/rViHL4aFL2Q==", "license": "Apache-2.0", "peer": true, "peerDependencies": { - "@maskito/core": "^3.10.0" + "@maskito/core": "^3.10.2" } }, "node_modules/@maskito/phone": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/@maskito/phone/-/phone-3.10.0.tgz", - "integrity": "sha512-FrjC0l/SyLvSH7w+MG9v3lVT3OnD098dVCBR8HZlL6l5oI1Y69LTEBgRrNWIso841V8AEmj1ryJwrjHWX/zF5Q==", + "version": "3.10.2", + "resolved": "https://registry.npmjs.org/@maskito/phone/-/phone-3.10.2.tgz", + "integrity": "sha512-XP/mp7CTHYriy6U+zoIitlJCGCmMr+yxtJ/u5y9+S4H3T1siILU3K8CAqetxpK//8/Zopco8lyz1D7ASKofdRg==", "license": "Apache-2.0", "peer": true, "peerDependencies": { - "@maskito/core": "^3.10.0", - "@maskito/kit": "^3.10.0", + "@maskito/core": "^3.10.2", + "@maskito/kit": "^3.10.2", "libphonenumber-js": ">=1.0.0" } }, @@ -4713,9 +4713,9 @@ "link": true }, "node_modules/@taiga-ui/addon-charts": { - "version": "4.44.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/addon-charts/-/addon-charts-4.44.0.tgz", - "integrity": "sha512-NiwY1P1NkDEOiSWgo3EGmXBWFmltmKA+Xkbu7fHnH7+8oenYLWd/orNvQEU5ey6qiSGj6wVr7kyeQMP8aau3NQ==", + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/addon-charts/-/addon-charts-4.47.0.tgz", + "integrity": "sha512-BLMw9zNBJp2tC9PyuG0+7j5VrAL4QFrngGvVlSALjWy9Caj/4mHaoDp9PUwAQrsuoFIMc6BwTbDdbO6/DJeVUQ==", "license": "Apache-2.0", "dependencies": { "tslib": ">=2.8.1" @@ -4724,15 +4724,15 @@ "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", "@ng-web-apis/common": "^4.12.0", - "@taiga-ui/cdk": "^4.44.0", - "@taiga-ui/core": "^4.44.0", + "@taiga-ui/cdk": "^4.47.0", + "@taiga-ui/core": "^4.47.0", "@taiga-ui/polymorpheus": "^4.9.0" } }, "node_modules/@taiga-ui/addon-commerce": { - "version": "4.44.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/addon-commerce/-/addon-commerce-4.44.0.tgz", - "integrity": "sha512-hpYDis6cFDewm1PR6CTXDoOvGmPbqJwcrl1wOyAfmGWCY4rle9+Jj1P1fW4tDMkOY/TVhQ3GIuSUYn/UZN9v4A==", + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/addon-commerce/-/addon-commerce-4.47.0.tgz", + "integrity": "sha512-Vh9kbQ47mUT6et3gc2/yJ7N6vebXDPRLHWBhpXxrXNVwel/dQT84NkvNBRJEPeSi2KRQNAy/qlxDdBVWUOFInw==", "license": "Apache-2.0", "dependencies": { "tslib": ">=2.8.1" @@ -4741,22 +4741,22 @@ "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", "@angular/forms": ">=16.0.0", - "@maskito/angular": "^3.10.0", - "@maskito/core": "^3.10.0", - "@maskito/kit": "^3.10.0", + "@maskito/angular": "^3.10.2", + "@maskito/core": "^3.10.2", + "@maskito/kit": "^3.10.2", "@ng-web-apis/common": "^4.12.0", - "@taiga-ui/cdk": "^4.44.0", - "@taiga-ui/core": "^4.44.0", - "@taiga-ui/i18n": "^4.44.0", - "@taiga-ui/kit": "^4.44.0", + "@taiga-ui/cdk": "^4.47.0", + "@taiga-ui/core": "^4.47.0", + "@taiga-ui/i18n": "^4.47.0", + "@taiga-ui/kit": "^4.47.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/addon-mobile": { - "version": "4.44.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/addon-mobile/-/addon-mobile-4.44.0.tgz", - "integrity": "sha512-NTV6DpyrI6Pv9FuXiYwOsOljyKkrKX+HJ35SRev1hrxzw9ECKrnOA1Q0aUCn09PgWIUY7rV+OXUZJ/w/Hmlm5Q==", + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/addon-mobile/-/addon-mobile-4.47.0.tgz", + "integrity": "sha512-rJeJUpXgEJyNNriiqLmVB7w8H+dSiECXjj1LRvSPffuL5bmvtBJKq8nw5Lpy+M3xeZz5qIMndJPNxSsKmkB0JA==", "license": "Apache-2.0", "dependencies": { "tslib": ">=2.8.1" @@ -4766,18 +4766,18 @@ "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", "@ng-web-apis/common": "^4.12.0", - "@taiga-ui/cdk": "^4.44.0", - "@taiga-ui/core": "^4.44.0", - "@taiga-ui/kit": "^4.44.0", - "@taiga-ui/layout": "^4.44.0", + "@taiga-ui/cdk": "^4.47.0", + "@taiga-ui/core": "^4.47.0", + "@taiga-ui/kit": "^4.47.0", + "@taiga-ui/layout": "^4.47.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/addon-table": { - "version": "4.44.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/addon-table/-/addon-table-4.44.0.tgz", - "integrity": "sha512-DmWZCPouoF21gWOpABepncWdg8W4Enk2z8FTiwGMsN0nGXmQ1SnU2QwEHCLumW2XNiNP8EHUpU42MZf9CuwIeA==", + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/addon-table/-/addon-table-4.47.0.tgz", + "integrity": "sha512-5ZarUauEfPhr+S+nJIXZjyifcvim6Yi00cADI+0PmgitolArjHEB4ZrdosS+Iqfqj9znKF6gPkcmDlv6i0eMCg==", "license": "Apache-2.0", "dependencies": { "tslib": ">=2.8.1" @@ -4786,18 +4786,18 @@ "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", "@ng-web-apis/intersection-observer": "^4.12.0", - "@taiga-ui/cdk": "^4.44.0", - "@taiga-ui/core": "^4.44.0", - "@taiga-ui/i18n": "^4.44.0", - "@taiga-ui/kit": "^4.44.0", + "@taiga-ui/cdk": "^4.47.0", + "@taiga-ui/core": "^4.47.0", + "@taiga-ui/i18n": "^4.47.0", + "@taiga-ui/kit": "^4.47.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/cdk": { - "version": "4.44.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/cdk/-/cdk-4.44.0.tgz", - "integrity": "sha512-4x0ISp+0oYhTC2E9SN2yDhA+rFC707m/rL4lf7RSTIbdefMyP3TdmsN2Emuhc0WSXcNs0OgYYEOaIx9jr7OqDw==", + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/cdk/-/cdk-4.47.0.tgz", + "integrity": "sha512-TqUg+7p/IZqlk34IB4/ZqTfw7HXifX2SqL9psCEmtW5Pg9zWN9of0S9g6Ccj9ALF+4Q4JxuHQf/xQdtAXdYdqg==", "license": "Apache-2.0", "dependencies": { "tslib": "2.8.1" @@ -4807,7 +4807,7 @@ "@angular-devkit/schematics": ">=16.0.0", "@schematics/angular": ">=16.0.0", "ng-morph": "^4.8.4", - "parse5": ">=7.3.0" + "parse5": "^7.3.0" }, "peerDependencies": { "@angular/animations": ">=16.0.0", @@ -4826,9 +4826,9 @@ } }, "node_modules/@taiga-ui/core": { - "version": "4.44.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/core/-/core-4.44.0.tgz", - "integrity": "sha512-KQPD63ZoFJKBZS/m1XkyTXDzUH3IYDcgNE3CVeZ9bmEkRwS0x7/fpFFdbr06sR/ej/eEzgop3LKOk4JHoQgFCA==", + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/core/-/core-4.47.0.tgz", + "integrity": "sha512-Z/6djJcMWn4/gFcdW6BDd7GU5tkGnidmfVFhSMCFoRYIY2YU7USjp6wYkjC9jhpRYZZVWVwY3IX4/GJGG5gLQg==", "license": "Apache-2.0", "dependencies": { "tslib": ">=2.8.1" @@ -4842,9 +4842,9 @@ "@angular/router": ">=16.0.0", "@ng-web-apis/common": "^4.12.0", "@ng-web-apis/mutation-observer": "^4.12.0", - "@taiga-ui/cdk": "^4.44.0", + "@taiga-ui/cdk": "^4.47.0", "@taiga-ui/event-plugins": "^4.6.0", - "@taiga-ui/i18n": "^4.44.0", + "@taiga-ui/i18n": "^4.47.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } @@ -4879,9 +4879,9 @@ } }, "node_modules/@taiga-ui/experimental": { - "version": "4.44.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/experimental/-/experimental-4.44.0.tgz", - "integrity": "sha512-ef/fSFjSOTwgsqRoWlwlXQkQrPcbuAlmEyGj4gMhdZC99HvKuYzUdihH4eZX4nx8fDyBOOZbM7QnW7ETQbKWHg==", + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/experimental/-/experimental-4.47.0.tgz", + "integrity": "sha512-EkswWcDKwtDhjA5A5oMtYHw9fnRBITpVb3cOwG45lQrlFBP0tipmx2QVlKKu0ga8VPjcv3W+b/pZsOWdp7UkJQ==", "license": "Apache-2.0", "dependencies": { "tslib": ">=2.8.1" @@ -4889,18 +4889,18 @@ "peerDependencies": { "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", - "@taiga-ui/addon-commerce": "^4.44.0", - "@taiga-ui/cdk": "^4.44.0", - "@taiga-ui/core": "^4.44.0", - "@taiga-ui/kit": "^4.44.0", + "@taiga-ui/addon-commerce": "^4.47.0", + "@taiga-ui/cdk": "^4.47.0", + "@taiga-ui/core": "^4.47.0", + "@taiga-ui/kit": "^4.47.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/i18n": { - "version": "4.44.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/i18n/-/i18n-4.44.0.tgz", - "integrity": "sha512-SnRQQPKI1k3Tkn17yByuB1ix4Nj9v70RLxVM84GX3okgQk2NIAj9hn8WXd36ljZUlcy7TqtJ+xlii0FqQVv7Sw==", + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/i18n/-/i18n-4.47.0.tgz", + "integrity": "sha512-TC9BugM8W7IgIXy3IoLtEWlxIb0xAxm17bfAtVLH9M8BfuQY6Jk0yHVQAspmaEz8pmaoLx9Tl2bXV9ugYG/ypA==", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -4913,18 +4913,18 @@ } }, "node_modules/@taiga-ui/icons": { - "version": "4.44.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/icons/-/icons-4.44.0.tgz", - "integrity": "sha512-KiIxxkG59kJDFV/g6e1YAbBff7y7EynNbmKY6sGo+CLcAQ52Y7Cz6i9us6ySf8fbOQRm4hKDXL3M10TKDeS+cg==", + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/icons/-/icons-4.47.0.tgz", + "integrity": "sha512-/SV6RdsCZoX5uUIlHiAPMLNNY7j8nxmE8NhGFtj4E5szx+V84LIKh2oES+zawPa7lIcVUT5M+FtXAtqdMiQa2g==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.3.0" } }, "node_modules/@taiga-ui/kit": { - "version": "4.44.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/kit/-/kit-4.44.0.tgz", - "integrity": "sha512-X8JNEE/WR7ftEx/bmibe2JTPOwge/o1VYHk1Z2vDx53e8JWWG+lLce2xx7NYexFPqP+4Ey2bPxn1Vx+rgGZYgA==", + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/kit/-/kit-4.47.0.tgz", + "integrity": "sha512-7LZNA4QInvB76Q38DRD1Ba2vIiKrpk4b/IoSmpahojYU1nrYByY69jGGD7ImxmCMJaIxymaODwHTcEJd3hW4Sw==", "license": "Apache-2.0", "dependencies": { "tslib": ">=2.8.1" @@ -4934,25 +4934,25 @@ "@angular/core": ">=16.0.0", "@angular/forms": ">=16.0.0", "@angular/router": ">=16.0.0", - "@maskito/angular": "^3.10.0", - "@maskito/core": "^3.10.0", - "@maskito/kit": "^3.10.0", - "@maskito/phone": "^3.10.0", + "@maskito/angular": "^3.10.2", + "@maskito/core": "^3.10.2", + "@maskito/kit": "^3.10.2", + "@maskito/phone": "^3.10.2", "@ng-web-apis/common": "^4.12.0", "@ng-web-apis/intersection-observer": "^4.12.0", "@ng-web-apis/mutation-observer": "^4.12.0", "@ng-web-apis/resize-observer": "^4.12.0", - "@taiga-ui/cdk": "^4.44.0", - "@taiga-ui/core": "^4.44.0", - "@taiga-ui/i18n": "^4.44.0", + "@taiga-ui/cdk": "^4.47.0", + "@taiga-ui/core": "^4.47.0", + "@taiga-ui/i18n": "^4.47.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/layout": { - "version": "4.44.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/layout/-/layout-4.44.0.tgz", - "integrity": "sha512-aidH7MgEAcz0nxauc5tm+0a5Z7PmG9bsSq+tsfkiOd6mV4BOf5xyYlpDyQn9gUBK8UYSxtMojp9Zs/2jH57gmw==", + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/layout/-/layout-4.47.0.tgz", + "integrity": "sha512-/P1dhno9/gvUT8lkbJGbNE8etm2D4G+2nRJAQwgj2Az2VePdR39nTOq0NKlGPyyjvSGi21/Mq2Hr5rRig3aglw==", "license": "Apache-2.0", "dependencies": { "tslib": ">=2.8.1" @@ -4960,17 +4960,17 @@ "peerDependencies": { "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", - "@taiga-ui/cdk": "^4.44.0", - "@taiga-ui/core": "^4.44.0", - "@taiga-ui/kit": "^4.44.0", + "@taiga-ui/cdk": "^4.47.0", + "@taiga-ui/core": "^4.47.0", + "@taiga-ui/kit": "^4.47.0", "@taiga-ui/polymorpheus": "^4.9.0", "rxjs": ">=7.0.0" } }, "node_modules/@taiga-ui/legacy": { - "version": "4.44.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/legacy/-/legacy-4.44.0.tgz", - "integrity": "sha512-vVXEj2BkKAS3ShOQ8OV6+j2yGFcRqtXMxZEU3kX8iM4fWRYS3C1669LLK7f0VzZd1miNex79SZx3NJM4Rvx7Kg==", + "version": "4.47.0", + "resolved": "https://registry.npmjs.org/@taiga-ui/legacy/-/legacy-4.47.0.tgz", + "integrity": "sha512-+82AOSKr2D/d8WSwdHZxW1BdL1fAh7HQEyhjCNT00hCaeQAeQ5QZNzDRX3qxFKwWZPWkC/sG8a/AtDtjkjB7Ew==", "license": "Apache-2.0", "dependencies": { "tslib": ">=2.8.1" @@ -8456,9 +8456,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.12.9", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.9.tgz", - "integrity": "sha512-VWwAdNeJgN7jFOD+wN4qx83DTPMVPPAUyx9/TUkBXKLiNkuWWk6anV0439tgdtwaJDrEdqkvdN22iA6J4bUCZg==", + "version": "1.12.10", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.10.tgz", + "integrity": "sha512-E91vHJD61jekHHR/RF/E83T/CMoaLXT7cwYA75T4gim4FZjnM6hbJjVIGg7chqlSqRsSvQ3izGmOjHy1SQzcGQ==", "license": "MIT", "peer": true }, diff --git a/web/package.json b/web/package.json index 86ee962ab..788aeb5d0 100644 --- a/web/package.json +++ b/web/package.json @@ -46,18 +46,18 @@ "@noble/hashes": "^1.4.0", "@start9labs/argon2": "^0.3.0", "@start9labs/start-sdk": "file:../sdk/baseDist", - "@taiga-ui/addon-charts": "4.44.0", - "@taiga-ui/addon-commerce": "4.44.0", - "@taiga-ui/addon-mobile": "4.44.0", - "@taiga-ui/addon-table": "4.44.0", - "@taiga-ui/cdk": "4.44.0", - "@taiga-ui/core": "4.44.0", + "@taiga-ui/addon-charts": "4.47.0", + "@taiga-ui/addon-commerce": "4.47.0", + "@taiga-ui/addon-mobile": "4.47.0", + "@taiga-ui/addon-table": "4.47.0", + "@taiga-ui/cdk": "4.47.0", + "@taiga-ui/core": "4.47.0", "@taiga-ui/event-plugins": "4.6.0", - "@taiga-ui/experimental": "4.44.0", - "@taiga-ui/icons": "4.44.0", - "@taiga-ui/kit": "4.44.0", - "@taiga-ui/layout": "4.44.0", - "@taiga-ui/legacy": "4.44.0", + "@taiga-ui/experimental": "4.47.0", + "@taiga-ui/icons": "4.47.0", + "@taiga-ui/kit": "4.47.0", + "@taiga-ui/layout": "4.47.0", + "@taiga-ui/legacy": "4.47.0", "@taiga-ui/polymorpheus": "4.9.0", "@taiga-ui/dompurify": "4.1.11", "ansi-to-html": "^0.7.2", diff --git a/web/projects/shared/src/i18n/dictionaries/de.ts b/web/projects/shared/src/i18n/dictionaries/de.ts index a404d9733..6f0969a99 100644 --- a/web/projects/shared/src/i18n/dictionaries/de.ts +++ b/web/projects/shared/src/i18n/dictionaries/de.ts @@ -539,4 +539,7 @@ export default { 543: 'Gateway ändern', 544: 'Standard-ACME ändern', 545: 'Keine Domains', + 546: 'Anbieter', + 547: 'DNS anzeigen', + 548: 'DNS testen', } satisfies i18n diff --git a/web/projects/shared/src/i18n/dictionaries/en.ts b/web/projects/shared/src/i18n/dictionaries/en.ts index 52425b7ae..3e41596cc 100644 --- a/web/projects/shared/src/i18n/dictionaries/en.ts +++ b/web/projects/shared/src/i18n/dictionaries/en.ts @@ -538,4 +538,7 @@ export const ENGLISH = { 'Change gateway': 543, // as in, change the network gateway for a computer 'Change default ACME': 544, // as in, change the default ACME provider for a domain 'No domains': 545, + 'Provider': 546, + 'Show DNS': 547, + 'Test DNS': 548, } as const diff --git a/web/projects/shared/src/i18n/dictionaries/es.ts b/web/projects/shared/src/i18n/dictionaries/es.ts index 882aa177e..ab18c0415 100644 --- a/web/projects/shared/src/i18n/dictionaries/es.ts +++ b/web/projects/shared/src/i18n/dictionaries/es.ts @@ -539,4 +539,7 @@ export default { 543: 'Cambiar puerta de enlace', 544: 'Cambiar ACME predeterminado', 545: 'Sin dominios', + 546: 'Proveedor', + 547: 'Mostrar DNS', + 548: 'Probar DNS', } satisfies i18n diff --git a/web/projects/shared/src/i18n/dictionaries/fr.ts b/web/projects/shared/src/i18n/dictionaries/fr.ts index 05b461f46..c780e1362 100644 --- a/web/projects/shared/src/i18n/dictionaries/fr.ts +++ b/web/projects/shared/src/i18n/dictionaries/fr.ts @@ -539,4 +539,7 @@ export default { 543: 'Changer de passerelle', 544: 'Changer l’ACME par défaut', 545: 'Aucun domaine', + 546: 'Fournisseur', + 547: 'Afficher le DNS', + 548: 'Tester le DNS', } satisfies i18n diff --git a/web/projects/shared/src/i18n/dictionaries/pl.ts b/web/projects/shared/src/i18n/dictionaries/pl.ts index 745506475..0feb88469 100644 --- a/web/projects/shared/src/i18n/dictionaries/pl.ts +++ b/web/projects/shared/src/i18n/dictionaries/pl.ts @@ -539,4 +539,7 @@ export default { 543: 'Zmień bramę', 544: 'Zmień domyślny ACME', 545: 'Brak domen', + 546: 'Dostawca', + 547: 'Pokaż DNS', + 548: 'Test DNS', } satisfies i18n diff --git a/web/projects/shared/src/services/dialog.service.ts b/web/projects/shared/src/services/dialog.service.ts index 64216fad0..448650b0c 100644 --- a/web/projects/shared/src/services/dialog.service.ts +++ b/web/projects/shared/src/services/dialog.service.ts @@ -49,13 +49,13 @@ export class DialogService { } }, ) { - options.data = options.data || {} - const { content, yes, no } = options.data + const { content, yes, no } = options.data || {} return this.dialogs.open(TUI_CONFIRM, { + ...options, label: this.i18n.transform(options.label), data: { - ...options.data, + ...(options.data || {}), content: isI18n(content) ? this.i18n.transform(content) : content, yes: this.i18n.transform(yes), no: this.i18n.transform(no), 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 bbec56f15..5516ed73e 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 @@ -24,5 +24,5 @@ import { i18nKey, i18nPipe } from '@start9labs/shared' imports: [i18nPipe], }) export class TableComponent { - readonly appTable = input.required>() + readonly appTable = input.required>() } diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/acme.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/acme.component.ts new file mode 100644 index 000000000..c3b67bd72 --- /dev/null +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/acme.component.ts @@ -0,0 +1,87 @@ +import { + ChangeDetectionStrategy, + Component, + inject, + input, +} from '@angular/core' +import { i18nPipe } from '@start9labs/shared' +import { + TuiButton, + TuiDataList, + TuiDropdown, + TuiTextfield, +} from '@taiga-ui/core' +import { toAcmeName } from 'src/app/utils/acme' + +import { AcmeService } from './acme.service' + +@Component({ + selector: 'tr[acme]', + template: ` + {{ toAcmeName(acme().url) }} + {{ acme().contact.join(', ') }} + + + + + + + + + + `, + styles: ` + td:last-child { + grid-area: 1 / 2 / 3; + align-self: center; + text-align: right; + } + + :host-context(tui-root._mobile) { + grid-template-columns: 1fr min-content; + + td:first-child { + font: var(--tui-font-text-m); + font-weight: bold; + } + } + `, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TuiButton, i18nPipe, TuiDropdown, TuiDataList, TuiTextfield], +}) +export class DomainsAcmeComponent { + protected readonly service = inject(AcmeService) + + readonly acme = input.required<{ url: string; contact: readonly string[] }>() + + open = false + + toAcmeName = toAcmeName +} diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/acme.service.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/acme.service.ts new file mode 100644 index 000000000..cd2158cb3 --- /dev/null +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/acme.service.ts @@ -0,0 +1,163 @@ +import { inject, Injectable } from '@angular/core' +import { + DialogService, + ErrorService, + i18nPipe, + LoadingService, +} from '@start9labs/shared' +import { ISB, utils } from '@start9labs/start-sdk' +import { filter } from 'rxjs' +import { FormComponent } from 'src/app/routes/portal/components/form.component' +import { ApiService } from 'src/app/services/api/embassy-api.service' +import { FormDialogService } from 'src/app/services/form-dialog.service' +import { knownACME } from 'src/app/utils/acme' +import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec' + +@Injectable({ + providedIn: 'root', +}) +export class AcmeService { + private readonly loader = inject(LoadingService) + private readonly errorService = inject(ErrorService) + private readonly api = inject(ApiService) + private readonly formDialog = inject(FormDialogService) + private readonly i18n = inject(i18nPipe) + private readonly dialog = inject(DialogService) + + async add(providers: { url: string; contact: string[] }[]) { + this.formDialog.open(FormComponent, { + label: 'Add ACME Provider', + data: { + spec: await configBuilderToSpec( + this.addSpec(providers.map(p => p.url)), + ), + buttons: [ + { + text: this.i18n.transform('Save'), + handler: async (val: ReturnType['_TYPE']) => { + const providerUrl = + val.provider.selection === 'other' + ? val.provider.value.url + : val.provider.selection + + return this.save(providerUrl, val.contact) + }, + }, + ], + }, + }) + } + + async edit({ url, contact }: { url: string; contact: readonly string[] }) { + this.formDialog.open(FormComponent, { + label: 'Edit ACME Provider', + data: { + spec: await configBuilderToSpec(this.editSpec()), + buttons: [ + { + text: this.i18n.transform('Save'), + handler: async (val: ReturnType['_TYPE']) => + this.save(url, val.contact), + }, + ], + value: { contact }, + }, + }) + } + + remove({ url }: { url: string }) { + this.dialog + .openConfirm({ label: 'Are you sure?', size: 's' }) + .pipe(filter(Boolean)) + .subscribe(async () => { + const loader = this.loader.open('Removing').subscribe() + + try { + await this.api.removeAcme({ provider: url }) + } catch (e: any) { + this.errorService.handleError(e) + } finally { + loader.unsubscribe() + } + }) + } + + private async save(providerUrl: string, contact: readonly string[]) { + const loader = this.loader.open('Saving').subscribe() + + try { + await this.api.initAcme({ + provider: new URL(providerUrl).href, + contact: contact.map(address => `mailto:${address}`), + }) + return true + } catch (e: any) { + this.errorService.handleError(e) + return false + } finally { + loader.unsubscribe() + } + } + + private addSpec(providers: string[]) { + const availableAcme = knownACME.filter( + acme => !providers.includes(acme.url), + ) + + return ISB.InputSpec.of({ + provider: ISB.Value.union({ + name: 'Provider', + default: (availableAcme[0]?.url as any) || 'other', + variants: ISB.Variants.of({ + ...availableAcme.reduce( + (obj, curr) => ({ + ...obj, + [curr.url]: { + name: curr.name, + spec: ISB.InputSpec.of({}), + }, + }), + {}, + ), + other: { + name: 'Other', + spec: ISB.InputSpec.of({ + url: ISB.Value.text({ + name: 'URL', + default: null, + required: true, + inputmode: 'url', + patterns: [utils.Patterns.url], + }), + }), + }, + }), + }), + contact: this.emailListSpec(), + }) + } + + private editSpec() { + return ISB.InputSpec.of({ + contact: this.emailListSpec(), + }) + } + + private emailListSpec() { + return ISB.Value.list( + ISB.List.text( + { + name: this.i18n.transform('Contact Emails')!, + description: this.i18n.transform( + 'Needed to obtain a certificate from a Certificate Authority', + ), + minLength: 1, + }, + { + inputmode: 'email', + patterns: [utils.Patterns.email], + }, + ), + ) + } +} diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/domain.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/domain.component.ts new file mode 100644 index 000000000..11251bc3e --- /dev/null +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/domain.component.ts @@ -0,0 +1,134 @@ +import { + ChangeDetectionStrategy, + Component, + inject, + input, +} from '@angular/core' +import { + DialogService, + ErrorService, + i18nPipe, + LoadingService, +} from '@start9labs/shared' +import { ISB } from '@start9labs/start-sdk' +import { + TuiButton, + TuiDataList, + TuiDropdown, + TuiTextfield, +} from '@taiga-ui/core' +import { filter } from 'rxjs' +import { FormComponent } from 'src/app/routes/portal/components/form.component' +import { FormDialogService } from 'src/app/services/form-dialog.service' +import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec' + +@Component({ + selector: 'tr[domain]', + template: ` + {{ domain().domain }} + {{ domain().gateway }} + {{ domain().acme }} + + + + + + + + + + + + `, + styles: ` + td:last-child { + grid-area: 1 / 2 / 4; + align-self: center; + text-align: right; + } + + :host-context(tui-root._mobile) { + grid-template-columns: 1fr min-content; + + td:first-child { + font: var(--tui-font-text-m); + font-weight: bold; + } + } + `, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [TuiButton, i18nPipe, TuiDropdown, TuiDataList, TuiTextfield], +}) +export class DomainsDomainComponent { + private readonly dialog = inject(DialogService) + private readonly loader = inject(LoadingService) + private readonly errorService = inject(ErrorService) + private readonly formDialog = inject(FormDialogService) + + readonly domain = input.required() + + open = false + + remove() { + this.dialog + .openConfirm({ label: 'Are you sure?', size: 's' }) + .pipe(filter(Boolean)) + .subscribe(async () => { + const loader = this.loader.open('Deleting').subscribe() + + try { + } catch (e: any) { + this.errorService.handleError(e) + } finally { + loader.unsubscribe() + } + }) + } + + async edit() { + const renameSpec = ISB.InputSpec.of({}) + + this.formDialog.open(FormComponent, { + label: 'Edit', + data: { + spec: await configBuilderToSpec(renameSpec), + buttons: [ + { + text: 'Save', + handler: (value: typeof renameSpec._TYPE) => {}, + }, + ], + }, + }) + } + + async showDns() {} + + async testDns() {} +} diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/domains.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/domains.component.ts index e2fc0ad6d..475769cb2 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/domains.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/domains.component.ts @@ -6,25 +6,15 @@ import { } from '@angular/core' import { toSignal } from '@angular/core/rxjs-interop' import { RouterLink } from '@angular/router' -import { - DocsLinkDirective, - ErrorService, - i18nPipe, - LoadingService, -} from '@start9labs/shared' -import { ISB, utils } from '@start9labs/start-sdk' -import { TuiButton, TuiLink, TuiLoader, TuiTitle } from '@taiga-ui/core' -import { TuiCell, TuiHeader } from '@taiga-ui/layout' +import { DocsLinkDirective, i18nPipe } from '@start9labs/shared' +import { TuiButton, TuiLink, TuiTitle } from '@taiga-ui/core' +import { 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' -import { PlaceholderComponent } from 'src/app/routes/portal/components/placeholder.component' -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 { knownACME, toAcmeName } from 'src/app/utils/acme' -import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec' + +import { AcmeService } from './acme.service' import { DomainsTableComponent } from './table.component' @Component({ @@ -65,46 +55,13 @@ import { DomainsTableComponent } from './table.component' size="xs" iconStart="@tui.plus" [style.margin-inline-start]="'auto'" - (click)="addAcme(value)" + (click)="service.add(value)" > {{ 'Add' | i18n }} } - @if (acme(); as value) { - @for (provider of value; track $index) { -
- - {{ toAcmeName(provider.url) }} - - {{ 'Contact' | i18n }}: {{ provider.contactString }} - - - - -
- } @empty { - - {{ 'No saved providers' | i18n }} - - } - } @else { - - } +
@@ -113,22 +70,20 @@ import { DomainsTableComponent } from './table.component' -
+
`, styles: ``, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ TuiButton, - TuiLoader, - TuiCell, TuiTitle, TuiHeader, TuiLink, @@ -136,179 +91,38 @@ import { DomainsTableComponent } from './table.component' TitleDirective, i18nPipe, DocsLinkDirective, - PlaceholderComponent, DomainsTableComponent, ], }) export default class SystemDomainsComponent { - private readonly formDialog = inject(FormDialogService) - private readonly loader = inject(LoadingService) - private readonly errorService = inject(ErrorService) - private readonly patch = inject>(PatchDB) - private readonly api = inject(ApiService) - private readonly i18n = inject(i18nPipe) + protected readonly patch = inject>(PatchDB) + protected readonly service = inject(AcmeService) - acme = toSignal( + readonly acme = toSignal( this.patch.watch$('serverInfo', 'network', 'acme').pipe( map(acme => - Object.keys(acme).map(url => { - const contact = + Object.keys(acme).map(url => ({ + url, + contact: acme[url]?.contact.map(mailto => mailto.replace('mailto:', '')) || - [] - return { - url, - contact, - contactString: contact.join(', '), - } - }), + [], + })), ), ), ) - domains = signal([]) - - toAcmeName = toAcmeName - - async addAcme( - providers: { - url: string - contact: string[] - contactString: string - }[], - ) { - this.formDialog.open(FormComponent, { - label: 'Add ACME Provider', - data: { - spec: await configBuilderToSpec( - this.addAcmeSpec(providers.map(p => p.url)), - ), - buttons: [ - { - text: this.i18n.transform('Save'), - handler: async ( - val: ReturnType['_TYPE'], - ) => { - const providerUrl = - val.provider.selection === 'other' - ? val.provider.value.url - : val.provider.selection - - return this.saveAcme(providerUrl, val.contact) - }, - }, - ], - }, - }) - } + readonly domains = signal([ + { + domain: 'blog.mydomain.com', + gateway: 'StartTunnel', + acme: 'System', + }, + { + domain: 'blog. mydomain.com', + gateway: 'StartTunnel', + acme: 'System', + }, + ]) async addDomain() {} - - async editAcme(provider: string, contact: string[]) { - this.formDialog.open(FormComponent, { - label: 'Edit ACME Provider', - data: { - spec: await configBuilderToSpec(this.editAcmeSpec()), - buttons: [ - { - text: this.i18n.transform('Save'), - handler: async ( - val: ReturnType['_TYPE'], - ) => this.saveAcme(provider, val.contact), - }, - ], - value: { contact }, - }, - }) - } - - async removeAcme(provider: string) { - const loader = this.loader.open('Removing').subscribe() - - try { - await this.api.removeAcme({ provider }) - } catch (e: any) { - this.errorService.handleError(e) - } finally { - loader.unsubscribe() - } - } - - private async saveAcme(providerUrl: string, contact: string[]) { - const loader = this.loader.open('Saving').subscribe() - - try { - await this.api.initAcme({ - provider: new URL(providerUrl).href, - contact: contact.map(address => `mailto:${address}`), - }) - return true - } catch (e: any) { - this.errorService.handleError(e) - return false - } finally { - loader.unsubscribe() - } - } - - private addAcmeSpec(providers: string[]) { - const availableAcme = knownACME.filter( - acme => !providers.includes(acme.url), - ) - - return ISB.InputSpec.of({ - provider: ISB.Value.union({ - name: 'Provider', - default: (availableAcme[0]?.url as any) || 'other', - variants: ISB.Variants.of({ - ...availableAcme.reduce( - (obj, curr) => ({ - ...obj, - [curr.url]: { - name: curr.name, - spec: ISB.InputSpec.of({}), - }, - }), - {}, - ), - other: { - name: 'Other', - spec: ISB.InputSpec.of({ - url: ISB.Value.text({ - name: 'URL', - default: null, - required: true, - inputmode: 'url', - patterns: [utils.Patterns.url], - }), - }), - }, - }), - }), - contact: this.emailListSpec(), - }) - } - - private editAcmeSpec() { - return ISB.InputSpec.of({ - contact: this.emailListSpec(), - }) - } - - private emailListSpec() { - return ISB.Value.list( - ISB.List.text( - { - name: this.i18n.transform('Contact Emails')!, - description: this.i18n.transform( - 'Needed to obtain a certificate from a Certificate Authority', - ), - minLength: 1, - }, - { - inputmode: 'email', - patterns: [utils.Patterns.email], - }, - ), - ) - } } diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/item.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/item.component.ts deleted file mode 100644 index f9e6d9ac0..000000000 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/item.component.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { - ChangeDetectionStrategy, - Component, - input, - output, -} from '@angular/core' -import { i18nPipe } from '@start9labs/shared' -import { - TuiButton, - TuiDataList, - TuiDropdown, - TuiOptGroup, -} from '@taiga-ui/core' - -@Component({ - selector: 'tr[domain]', - template: ` - - - - - - - - - - - - - - - - - `, - styles: ` - td:last-child { - grid-area: 3 / span 4; - white-space: nowrap; - text-align: right; - flex-direction: row-reverse; - justify-content: flex-end; - gap: 0.5rem; - } - - :host-context(tui-root._mobile) { - display: grid; - grid-template-columns: repeat(3, min-content) 1fr; - align-items: center; - padding: 1rem 0.5rem; - gap: 0.5rem; - - td { - display: flex; - padding: 0; - } - } - `, - changeDetection: ChangeDetectionStrategy.OnPush, - imports: [TuiButton, i18nPipe, TuiDropdown, TuiDataList, TuiOptGroup], -}) -export class DomainsItemComponent { - readonly domain = input.required() - - onEdit = output() - onShowDns = output() - onTestDns = output() - onRemove = output() - - open = false -} diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/table.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/table.component.ts index 6a0de08db..4c0dcf5e3 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/table.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/domains/table.component.ts @@ -1,110 +1,68 @@ import { ChangeDetectionStrategy, Component, - inject, + computed, input, } from '@angular/core' -import { - DialogService, - ErrorService, - i18nPipe, - LoadingService, -} from '@start9labs/shared' -import { ISB } from '@start9labs/start-sdk' +import { i18nPipe } from '@start9labs/shared' import { TuiSkeleton } from '@taiga-ui/kit' -import { filter } from 'rxjs' -import { FormComponent } from 'src/app/routes/portal/components/form.component' -import { ApiService } from 'src/app/services/api/embassy-api.service' -import { FormDialogService } from 'src/app/services/form-dialog.service' -import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec' -import { TableComponent } from 'src/app/routes/portal/components/table.component' -import { DomainsItemComponent } from './item.component' import { PlaceholderComponent } from 'src/app/routes/portal/components/placeholder.component' +import { TableComponent } from 'src/app/routes/portal/components/table.component' + +import { DomainsAcmeComponent } from './acme.component' +import { DomainsDomainComponent } from './domain.component' @Component({ - selector: '[domains]', + selector: 'domains-table', template: ` - - @for (domain of domains(); track $index) { - - } @empty { - @if (domains()) { - - {{ 'No domains' | i18n }} - - } @else { - - - +
-
{{ 'Loading' | i18n }}
-
+ @for (item of items(); track $index) { + @if (mode() === 'domains') { + + } @else if (mode() === 'acme') { + } + } @empty { + + + }
+ @if (items()) { + + @if (mode() === 'domains') { + {{ 'No domains' | i18n }} + } @else { + {{ 'No saved providers' | i18n }} + } + + } @else { +
{{ 'Loading' | i18n }}
+ } +
`, - styles: ` - :host { - grid-column: span 6; - } - `, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ TuiSkeleton, i18nPipe, TableComponent, - DomainsItemComponent, PlaceholderComponent, + DomainsDomainComponent, + DomainsAcmeComponent, ], }) -export class DomainsTableComponent { - readonly domains = input(null) +export class DomainsTableComponent { + // @TODO Alex proper types + readonly items = input() + readonly mode = input<'domains' | 'acme'>('domains') - private readonly dialog = inject(DialogService) - private readonly loader = inject(LoadingService) - private readonly errorService = inject(ErrorService) - private readonly api = inject(ApiService) - private readonly formDialog = inject(FormDialogService) + readonly titles = computed(() => + this.mode() === 'domains' + ? (['Domain', 'Gateway', 'Default ACME', null] as const) + : (['Provider', 'Contact', null] as const), + ) - remove(domain: any) { - this.dialog - .openConfirm({ label: 'Are you sure?', size: 's' }) - .pipe(filter(Boolean)) - .subscribe(async () => { - const loader = this.loader.open('Deleting').subscribe() - - try { - } catch (e: any) { - this.errorService.handleError(e) - } finally { - loader.unsubscribe() - } - }) - } - - async edit(domain: any) { - const renameSpec = ISB.InputSpec.of({}) - - this.formDialog.open(FormComponent, { - label: 'Edit', - data: { - spec: await configBuilderToSpec(renameSpec), - buttons: [ - { - text: 'Save', - handler: (value: typeof renameSpec._TYPE) => {}, - }, - ], - }, - }) - } - - async showDns(domain: any) {} - - async testDns(domain: any) {} + readonly icon = computed(() => + this.mode() === 'domains' ? '@tui.globe' : '@tui.shield-question', + ) } diff --git a/web/projects/ui/src/app/routes/portal/routes/system/system.const.ts b/web/projects/ui/src/app/routes/portal/routes/system/system.const.ts index a1f527bcd..07a3485b2 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/system.const.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/system.const.ts @@ -40,14 +40,14 @@ export const SYSTEM_MENU = [ [ { icon: '@tui.globe', - item: 'Gateways', - link: 'gateways', - }, - { - icon: '@tui.award', item: 'Domains', link: 'domains', }, + { + icon: '@tui.door-open', + item: 'Gateways', + link: 'gateways', + }, ], [ {