diff --git a/core/startos/bindings/PackageDataEntry.ts b/core/startos/bindings/PackageDataEntry.ts index 8b906bb90..5729e6bc3 100644 --- a/core/startos/bindings/PackageDataEntry.ts +++ b/core/startos/bindings/PackageDataEntry.ts @@ -16,6 +16,7 @@ export type PackageDataEntry = { developerKey: string; icon: DataUrl; lastBackup: string | null; + nextBackup: string | null; currentDependencies: CurrentDependencies; actions: { [key: ActionId]: ActionMetadata }; serviceInterfaces: { diff --git a/web/package-lock.json b/web/package-lock.json index 36c57fedc..a5ab3874a 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -23,17 +23,17 @@ "@start9labs/argon2": "^0.1.0", "@start9labs/emver": "^0.1.5", "@start9labs/start-sdk": "file:../sdk/dist", - "@taiga-ui/addon-charts": "3.73.0", - "@taiga-ui/addon-commerce": "3.73.0", - "@taiga-ui/addon-mobile": "3.73.0", - "@taiga-ui/cdk": "3.73.0", - "@taiga-ui/core": "3.73.0", - "@taiga-ui/experimental": "3.73.0", - "@taiga-ui/icons": "3.73.0", - "@taiga-ui/kit": "3.73.0", - "@taiga-ui/styles": "3.73.0", + "@taiga-ui/addon-charts": "3.77.1", + "@taiga-ui/addon-commerce": "3.77.1", + "@taiga-ui/addon-mobile": "3.77.1", + "@taiga-ui/cdk": "3.77.1", + "@taiga-ui/core": "3.77.1", + "@taiga-ui/experimental": "3.77.1", + "@taiga-ui/icons": "3.77.1", + "@taiga-ui/kit": "3.77.1", + "@taiga-ui/styles": "3.77.1", "@tinkoff/ng-dompurify": "4.0.0", - "@tinkoff/ng-event-plugins": "3.1.1", + "@tinkoff/ng-event-plugins": "3.2.0", "ansi-to-html": "^0.7.2", "base64-js": "^1.5.1", "cbor": "npm:@jprochazk/cbor@^0.4.9", @@ -5085,72 +5085,72 @@ "link": true }, "node_modules/@taiga-ui/addon-charts": { - "version": "3.73.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/addon-charts/-/addon-charts-3.73.0.tgz", - "integrity": "sha512-4zK0sXqMtuz2fVlsgbnBLMuzphCqLbsSR/owMzJxAsrlZV7Lv1VUaMHHe9sdhDBmvO3VZu2d1wNuv/Z1jVfpYQ==", + "version": "3.77.1", + "resolved": "https://registry.npmjs.org/@taiga-ui/addon-charts/-/addon-charts-3.77.1.tgz", + "integrity": "sha512-yk9cvMewoRRVxTv1sIorVgO9GBkleQyRzkT774RPQACQHizGS2Sq5dQMtetwD3usPmLR2GblDR6NM+iOyHhMIA==", "dependencies": { - "tslib": "2.6.2" + "tslib": "^2.6.2" }, "peerDependencies": { "@angular/common": ">=12.0.0", "@angular/core": ">=12.0.0", - "@ng-web-apis/common": "3.0.6", - "@taiga-ui/cdk": "^3.73.0", - "@taiga-ui/core": "^3.73.0", - "@tinkoff/ng-polymorpheus": "4.3.0" + "@ng-web-apis/common": "^3.0.6", + "@taiga-ui/cdk": "^3.77.1", + "@taiga-ui/core": "^3.77.1", + "@tinkoff/ng-polymorpheus": "^4.3.0" } }, "node_modules/@taiga-ui/addon-commerce": { - "version": "3.73.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/addon-commerce/-/addon-commerce-3.73.0.tgz", - "integrity": "sha512-LVK1ROrutavqIvOEHCaXRcX9ZNyznz3cCQFhbLldTIgTSXoYQNNitAgG4cRmntLioLupcVnKt0JZOHiObEx49A==", + "version": "3.77.1", + "resolved": "https://registry.npmjs.org/@taiga-ui/addon-commerce/-/addon-commerce-3.77.1.tgz", + "integrity": "sha512-4qNgDZfxyzTHQdKaerw28xP8d2PCuumLM9xjlRbNE5XcnhUI+rccgZOV9MtZtQoNBl++OBPmbaT2/9+zbSqbxg==", "dependencies": { - "tslib": "2.6.2" + "tslib": "^2.6.2" }, "peerDependencies": { "@angular/common": ">=12.0.0", "@angular/core": ">=12.0.0", "@angular/forms": ">=12.0.0", - "@maskito/angular": "1.9.0", - "@maskito/core": "1.9.0", - "@maskito/kit": "1.9.0", - "@ng-web-apis/common": "3.0.6", - "@taiga-ui/cdk": "^3.73.0", - "@taiga-ui/core": "^3.73.0", - "@taiga-ui/i18n": "^3.73.0", - "@taiga-ui/kit": "^3.73.0", - "@tinkoff/ng-polymorpheus": "4.3.0", + "@maskito/angular": "^1.9.0", + "@maskito/core": "^1.9.0", + "@maskito/kit": "^1.9.0", + "@ng-web-apis/common": "^3.0.6", + "@taiga-ui/cdk": "^3.77.1", + "@taiga-ui/core": "^3.77.1", + "@taiga-ui/i18n": "^3.77.1", + "@taiga-ui/kit": "^3.77.1", + "@tinkoff/ng-polymorpheus": "^4.3.0", "rxjs": ">=6.0.0" } }, "node_modules/@taiga-ui/addon-mobile": { - "version": "3.73.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/addon-mobile/-/addon-mobile-3.73.0.tgz", - "integrity": "sha512-XJ8xlmnp3fU02KjqgFtUCkcMsPmdIvksI/vmK7ZCaNunsGIYVAGSqw3/yyRV+HkX1ccqynX5johv+lligD9RtA==", + "version": "3.77.1", + "resolved": "https://registry.npmjs.org/@taiga-ui/addon-mobile/-/addon-mobile-3.77.1.tgz", + "integrity": "sha512-kRa9uNdnY9Tyz8FdGXqgbL7cKZ1Z43K3Kjey9tX3uf4BEkODPNVuQFTNzuZvOt6/ql+XtPxi/hU19ii5rvKz3A==", "dependencies": { - "tslib": "2.6.2" + "tslib": "^2.6.2" }, "peerDependencies": { "@angular/cdk": ">=12.0.0", "@angular/common": ">=12.0.0", "@angular/core": ">=12.0.0", - "@ng-web-apis/common": "3.0.6", - "@taiga-ui/cdk": "^3.73.0", - "@taiga-ui/core": "^3.73.0", - "@taiga-ui/kit": "^3.73.0", - "@tinkoff/ng-polymorpheus": "4.3.0", + "@ng-web-apis/common": "^3.0.6", + "@taiga-ui/cdk": "^3.77.1", + "@taiga-ui/core": "^3.77.1", + "@taiga-ui/kit": "^3.77.1", + "@tinkoff/ng-polymorpheus": "^4.3.0", "rxjs": ">=6.0.0" } }, "node_modules/@taiga-ui/cdk": { - "version": "3.73.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/cdk/-/cdk-3.73.0.tgz", - "integrity": "sha512-bxgbetJcbB+9h6ZO0ht076A9K0UOemr5D339o8h2tQpFnjOiw7gQ0ZnpNrKXXOpb5eASnptulmwtITvagpE1lg==", + "version": "3.77.1", + "resolved": "https://registry.npmjs.org/@taiga-ui/cdk/-/cdk-3.77.1.tgz", + "integrity": "sha512-mqT1Rz/JWqah4aNVRD3iEND4XdkfsOxV100D0gbdFD5/aaiMTyL6oMEP2GGE0lSsuk1mRCixkDW0qPCbhG21yQ==", "dependencies": { "@ng-web-apis/common": "3.0.6", "@ng-web-apis/mutation-observer": "3.1.0", "@ng-web-apis/resize-observer": "3.0.6", - "@tinkoff/ng-event-plugins": "3.1.1", + "@tinkoff/ng-event-plugins": "3.2.0", "@tinkoff/ng-polymorpheus": "4.3.0", "tslib": "2.6.2" }, @@ -5172,12 +5172,12 @@ "optional": true }, "node_modules/@taiga-ui/core": { - "version": "3.73.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/core/-/core-3.73.0.tgz", - "integrity": "sha512-zQ+qhgBxQK6+SrzfSHIotKI00xbPu0ZTBFyYGUT8zD0If4aN5oeR+Q5A9kUb/0rEPsHcg04TcAEtAsAtG2l/oA==", + "version": "3.77.1", + "resolved": "https://registry.npmjs.org/@taiga-ui/core/-/core-3.77.1.tgz", + "integrity": "sha512-RjrOZtkQbb+Hw+7wMTt8j76OkGiLrCDb2Ol1rmngFQfzPX5OlaRkBtNhCNoyBtI9rl4CCX2/ViCGnGmrIkHu6g==", "dependencies": { - "@taiga-ui/i18n": "^3.73.0", - "tslib": "2.6.2" + "@taiga-ui/i18n": "^3.77.1", + "tslib": "^2.6.2" }, "peerDependencies": { "@angular/animations": ">=12.0.0", @@ -5186,68 +5186,68 @@ "@angular/forms": ">=12.0.0", "@angular/platform-browser": ">=12.0.0", "@angular/router": ">=12.0.0", - "@ng-web-apis/common": "3.0.6", - "@ng-web-apis/mutation-observer": "3.1.0", - "@taiga-ui/cdk": "^3.73.0", - "@taiga-ui/i18n": "^3.73.0", - "@tinkoff/ng-event-plugins": "3.1.1", - "@tinkoff/ng-polymorpheus": "4.3.0", + "@ng-web-apis/common": "^3.0.6", + "@ng-web-apis/mutation-observer": "^3.1.0", + "@taiga-ui/cdk": "^3.77.1", + "@taiga-ui/i18n": "^3.77.1", + "@tinkoff/ng-event-plugins": "^3.2.0", + "@tinkoff/ng-polymorpheus": "^4.3.0", "rxjs": ">=6.0.0" } }, "node_modules/@taiga-ui/experimental": { - "version": "3.73.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/experimental/-/experimental-3.73.0.tgz", - "integrity": "sha512-FlMrasE7emFTNCN2a6xdU9ZCH7HIAU/xd+jjqxsi9Cf37juDLFtInFjFyQ9ZuEnhIJP3POTX+d8t/niRTPwpNw==", + "version": "3.77.1", + "resolved": "https://registry.npmjs.org/@taiga-ui/experimental/-/experimental-3.77.1.tgz", + "integrity": "sha512-UVmP0y1w9VvOoQoTH4VByZ3m45OcC0Lw//rsrNMicPCX9b5IJxgEjUAmJ+PZ/ecsgnDVKO0HD18cZt5uCVdy7w==", "dependencies": { - "tslib": "2.6.2" + "tslib": "^2.6.2" }, "peerDependencies": { "@angular/common": ">=12.0.0", "@angular/core": ">=12.0.0", - "@taiga-ui/addon-commerce": "^3.73.0", - "@taiga-ui/cdk": "^3.73.0", - "@taiga-ui/core": "^3.73.0", - "@taiga-ui/kit": "^3.73.0", - "@tinkoff/ng-polymorpheus": "4.3.0", + "@taiga-ui/addon-commerce": "^3.77.1", + "@taiga-ui/cdk": "^3.77.1", + "@taiga-ui/core": "^3.77.1", + "@taiga-ui/kit": "^3.77.1", + "@tinkoff/ng-polymorpheus": "^4.3.0", "rxjs": ">=6.0.0" } }, "node_modules/@taiga-ui/i18n": { - "version": "3.73.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/i18n/-/i18n-3.73.0.tgz", - "integrity": "sha512-CLyYmnnL08+P5XvnKSMhZPpJyBs4199ApMX33hPBa4MvpmykUoVXQ0nXslLECSqAcfL39N9tzWKnxyLAavXjNw==", + "version": "3.77.1", + "resolved": "https://registry.npmjs.org/@taiga-ui/i18n/-/i18n-3.77.1.tgz", + "integrity": "sha512-rC2RYMFyaRHKcoU5WUKMe2DU0urRNh0daKvRIhp8t5AnTQE1MDZHRJYVCpysr8sfXvtJdr5oHoZccavzvqjqOQ==", "dependencies": { - "tslib": "2.6.2" + "tslib": "^2.6.2" }, "peerDependencies": { "@angular/core": ">=12.0.0", - "@ng-web-apis/common": "3.0.6", + "@ng-web-apis/common": "^3.0.6", "rxjs": ">=6.0.0" } }, "node_modules/@taiga-ui/icons": { - "version": "3.73.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/icons/-/icons-3.73.0.tgz", - "integrity": "sha512-3/B9NW/gQ4ad+voS57TSuz7cCElh1hcqUil4wP2P8pwS3HzgScokZpvVQs6u5jZ0Xt4v7uG4pac6pwGVsC8ndA==", + "version": "3.77.1", + "resolved": "https://registry.npmjs.org/@taiga-ui/icons/-/icons-3.77.1.tgz", + "integrity": "sha512-e9NXwxOktKM9TVDVePVkTFAuAs9jlhZCKzpAOfrme1bHVQJ1MEhD2hdj74Yn7IGKOCFjrUDQnxJ9w9POh6H9Vg==", "dependencies": { - "tslib": "2.6.2" + "tslib": "^2.6.2" }, "peerDependencies": { - "@taiga-ui/cdk": "^3.73.0" + "@taiga-ui/cdk": "^3.77.1" } }, "node_modules/@taiga-ui/kit": { - "version": "3.73.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/kit/-/kit-3.73.0.tgz", - "integrity": "sha512-AKPjxkcKnMA4TeL5f6gBjgnJff7JJfh2YmOxHPcXXcBy/BeXzY+Lfmlgqz0P8Rtz01JouCZpWIWNayb2cGlq5g==", + "version": "3.77.1", + "resolved": "https://registry.npmjs.org/@taiga-ui/kit/-/kit-3.77.1.tgz", + "integrity": "sha512-Pyk44wDF61VZiMQHehQ3KEEBj5AsO3et8QccKwmqr13jaQzmH6ljwbbYJOwPpEVsdZbqfiI56OVxp86mi6F8mw==", "dependencies": { "@maskito/angular": "1.9.0", "@maskito/core": "1.9.0", "@maskito/kit": "1.9.0", "@ng-web-apis/intersection-observer": "3.2.0", "text-mask-core": "5.1.2", - "tslib": "2.6.2" + "tslib": "^2.6.2" }, "peerDependencies": { "@angular/common": ">=12.0.0", @@ -5255,22 +5255,22 @@ "@angular/forms": ">=12.0.0", "@angular/router": ">=12.0.0", "@ng-web-apis/common": "3.0.6", - "@ng-web-apis/mutation-observer": "3.1.0", - "@ng-web-apis/resize-observer": "3.0.6", - "@taiga-ui/cdk": "^3.73.0", - "@taiga-ui/core": "^3.73.0", - "@taiga-ui/i18n": "^3.73.0", - "@tinkoff/ng-polymorpheus": "4.3.0", + "@ng-web-apis/mutation-observer": "^3.1.0", + "@ng-web-apis/resize-observer": "^3.0.6", + "@taiga-ui/cdk": "^3.77.1", + "@taiga-ui/core": "^3.77.1", + "@taiga-ui/i18n": "^3.77.1", + "@tinkoff/ng-polymorpheus": "^4.3.0", "rxjs": ">=6.0.0" } }, "node_modules/@taiga-ui/styles": { - "version": "3.73.0", - "resolved": "https://registry.npmjs.org/@taiga-ui/styles/-/styles-3.73.0.tgz", - "integrity": "sha512-hFInEKxsI4fj5KZCIGzH/zY00YwE2PsUoAlzoeGqpfnOG5rY/2WFpZnLrj7yJCOkFzsFy9KUZC00d46w50ijnQ==", + "version": "3.77.1", + "resolved": "https://registry.npmjs.org/@taiga-ui/styles/-/styles-3.77.1.tgz", + "integrity": "sha512-YoPXqY1pz+13vYhHnE6hskjRtnDDGgjnZIPtx05ChN8/TDIJ6NiaWKI5Es/G4fq3vKJnq2yIZ9D2Ghm/aPItGw==", "peerDependencies": { - "@taiga-ui/cdk": "^3.73.0", - "tslib": "2.6.2" + "@taiga-ui/cdk": "^3.77.1", + "tslib": "^2.6.2" } }, "node_modules/@tinkoff/ng-dompurify": { @@ -5287,9 +5287,9 @@ } }, "node_modules/@tinkoff/ng-event-plugins": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@tinkoff/ng-event-plugins/-/ng-event-plugins-3.1.1.tgz", - "integrity": "sha512-JC64sdpiOHmq4rZBFzqVweQoPxN7afoCuebKayEELEODho6oYiTVyM3P9T9JWUyzieSujDP7um7fiCggrWc83A==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@tinkoff/ng-event-plugins/-/ng-event-plugins-3.2.0.tgz", + "integrity": "sha512-n56R5xNfiytabh2WmWdQXfNU6m7dfOo3LLxlARE+DX7f5yciW2xBdDkuEHX74q8dlCuAVlW9aslSfz8c//ymwA==", "dependencies": { "tslib": "^2.2.0" }, diff --git a/web/package.json b/web/package.json index eeb0a5000..dea30cefb 100644 --- a/web/package.json +++ b/web/package.json @@ -45,17 +45,17 @@ "@start9labs/argon2": "^0.1.0", "@start9labs/emver": "^0.1.5", "@start9labs/start-sdk": "file:../sdk/dist", - "@taiga-ui/addon-charts": "3.73.0", - "@taiga-ui/addon-commerce": "3.73.0", - "@taiga-ui/addon-mobile": "3.73.0", - "@taiga-ui/cdk": "3.73.0", - "@taiga-ui/core": "3.73.0", - "@taiga-ui/experimental": "3.73.0", - "@taiga-ui/icons": "3.73.0", - "@taiga-ui/kit": "3.73.0", - "@taiga-ui/styles": "3.73.0", + "@taiga-ui/addon-charts": "3.77.1", + "@taiga-ui/addon-commerce": "3.77.1", + "@taiga-ui/addon-mobile": "3.77.1", + "@taiga-ui/cdk": "3.77.1", + "@taiga-ui/core": "3.77.1", + "@taiga-ui/experimental": "3.77.1", + "@taiga-ui/icons": "3.77.1", + "@taiga-ui/kit": "3.77.1", + "@taiga-ui/styles": "3.77.1", "@tinkoff/ng-dompurify": "4.0.0", - "@tinkoff/ng-event-plugins": "3.1.1", + "@tinkoff/ng-event-plugins": "3.2.0", "ansi-to-html": "^0.7.2", "base64-js": "^1.5.1", "cbor": "npm:@jprochazk/cbor@^0.4.9", diff --git a/web/projects/ui/src/app/routes/portal/routes/service/components/backups.component.ts b/web/projects/ui/src/app/routes/portal/routes/service/components/backups.component.ts index e36ec202b..42d0d0230 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/components/backups.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/components/backups.component.ts @@ -1,19 +1,26 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core' +import { I18nPluralPipe } from '@angular/common' +import { + ChangeDetectionStrategy, + Component, + computed, + input, +} from '@angular/core' import { RouterLink } from '@angular/router' +import { PackageDataEntry } from '@startos' import { TuiButtonModule } from '@taiga-ui/experimental' @Component({ selector: 'service-backups', template: ` -
+
Last backup - 6 days ago + {{ previous() | i18nPlural: ago }}
-
+
Next backup - Not scheduled + {{ next() | i18nPlural: in }}
-
+
:last-child { - min-width: 100%; - padding-bottom: 1rem; - } + padding-bottom: 1rem; small { display: block; @@ -46,6 +49,34 @@ import { TuiButtonModule } from '@taiga-ui/experimental' `, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [TuiButtonModule, RouterLink], + imports: [TuiButtonModule, RouterLink, I18nPluralPipe], }) -export class ServiceBackupsComponent {} +export class ServiceBackupsComponent { + pkg = input.required() + + readonly previous = computed(() => + daysBetween(new Date(), new Date(this.pkg().lastBackup || new Date())), + ) + + readonly next = computed(() => + daysBetween(new Date(), new Date(this.pkg().nextBackup || new Date())), + ) + + readonly ago = { + '=0': 'Never performed', + '=1': 'day ago', + other: '# days ago', + } + + readonly in = { + '=0': 'Not scheduled', + '=1': 'Tomorrow', + other: 'In # days', + } +} + +function daysBetween(one: Date, two: Date): number { + return Math.abs( + Math.round((one.valueOf() - two.valueOf()) / (1000 * 60 * 60 * 24)), + ) +} diff --git a/web/projects/ui/src/app/routes/portal/routes/service/routes/service.component.ts b/web/projects/ui/src/app/routes/portal/routes/service/routes/service.component.ts index e67b1f531..75c6e4ec0 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/routes/service.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/routes/service.component.ts @@ -65,7 +65,7 @@ import { DependencyInfo } from '../types/dependency-info' @if (isInstalled(service)) {

Backups

- +
diff --git a/web/projects/ui/src/app/services/api/api.fixures.ts b/web/projects/ui/src/app/services/api/api.fixures.ts index b62f73e28..87d14abaf 100644 --- a/web/projects/ui/src/app/services/api/api.fixures.ts +++ b/web/projects/ui/src/app/services/api/api.fixures.ts @@ -913,7 +913,7 @@ export module Mock { integer: false, }), }), - displayAs: 'I\'m {{last-name}}, {{first-name}} {{last-name}}', + displayAs: `I'm {{last-name}}, {{first-name}} {{last-name}}`, uniqueBy: 'last-name', }, ), @@ -1295,6 +1295,7 @@ export module Mock { icon: '/assets/img/service-icons/bitcoind.svg', installedAt: new Date().toISOString(), lastBackup: null, + nextBackup: null, status: { configured: true, main: { @@ -1539,6 +1540,7 @@ export module Mock { icon: '/assets/img/service-icons/btc-rpc-proxy.png', installedAt: new Date().toISOString(), lastBackup: null, + nextBackup: null, status: { configured: false, main: { @@ -1681,6 +1683,7 @@ export module Mock { icon: '/assets/img/service-icons/lnd.png', installedAt: new Date().toISOString(), lastBackup: null, + nextBackup: null, status: { configured: true, main: { diff --git a/web/projects/ui/src/app/services/api/mock-patch.ts b/web/projects/ui/src/app/services/api/mock-patch.ts index 8cb16e8fa..6d04898a2 100644 --- a/web/projects/ui/src/app/services/api/mock-patch.ts +++ b/web/projects/ui/src/app/services/api/mock-patch.ts @@ -146,7 +146,8 @@ export const mockPatchData: DataModel = { }, icon: '/assets/img/service-icons/bitcoind.svg', installedAt: new Date().toISOString(), - lastBackup: null, + lastBackup: new Date(new Date().valueOf() - 604800001).toISOString(), + nextBackup: new Date(new Date().valueOf() + 100000000).toISOString(), status: { configured: true, main: { @@ -419,6 +420,7 @@ export const mockPatchData: DataModel = { icon: '/assets/img/service-icons/lnd.png', installedAt: new Date().toISOString(), lastBackup: null, + nextBackup: null, status: { configured: true, main: { diff --git a/web/projects/ui/src/app/services/patch-db/data-model.ts b/web/projects/ui/src/app/services/patch-db/data-model.ts index 072b9d254..b3cf2dc2c 100644 --- a/web/projects/ui/src/app/services/patch-db/data-model.ts +++ b/web/projects/ui/src/app/services/patch-db/data-model.ts @@ -131,6 +131,7 @@ export type PackageDataEntry = stateInfo: T installedAt: string outboundProxy: string | null + nextBackup: string | null } export type StateInfo = InstalledState | InstallingState | UpdatingState