diff --git a/web/projects/marketplace/src/pages/show/additional/additional.component.scss b/web/projects/marketplace/src/pages/show/additional/additional.component.scss index 0a8c0e199..c8c41396e 100644 --- a/web/projects/marketplace/src/pages/show/additional/additional.component.scss +++ b/web/projects/marketplace/src/pages/show/additional/additional.component.scss @@ -10,7 +10,7 @@ & > * + * { border-top-width: 1px; - border-bottom-width: 0px; + border-bottom-width: 0; border-color: rgb(113 113 122); } } diff --git a/web/projects/shared/styles/taiga.scss b/web/projects/shared/styles/taiga.scss index 5adcc6739..c68065da5 100644 --- a/web/projects/shared/styles/taiga.scss +++ b/web/projects/shared/styles/taiga.scss @@ -9,7 +9,7 @@ /* stylelint-disable order/order */ [tuiAppearance][data-appearance='secondary-warning'] { background: var(--tui-warning-bg); - color: var(--tui-warning-fill); + color: var(--tui-text-01); @include appearance-hover { background: var(--tui-warning-bg-hover); @@ -58,6 +58,7 @@ @include appearance-disabled { background: #eaecee; + color: #333; } } @@ -75,6 +76,7 @@ @include appearance-disabled { background: #eaecee; + color: #333; } } @@ -92,6 +94,7 @@ @include appearance-disabled { background: #eaecee; + color: #333; } } @@ -109,6 +112,7 @@ @include appearance-disabled { background: #eaecee; + color: #333; } } @@ -126,6 +130,7 @@ @include appearance-disabled { background: #eaecee; + color: #333; } } diff --git a/web/projects/ui/src/app/routes/portal/components/form/form-object/form-object.component.html b/web/projects/ui/src/app/routes/portal/components/form/form-object/form-object.component.html index aa9e85f19..6dccad33a 100644 --- a/web/projects/ui/src/app/routes/portal/components/form/form-object/form-object.component.html +++ b/web/projects/ui/src/app/routes/portal/components/form/form-object/form-object.component.html @@ -7,7 +7,7 @@ class="button" [class.button_open]="open" [style.border-radius.%]="100" - [appearance]="invalid ? 'secondary-destructive' : 'secondary'" + [appearance]="invalid ? 'danger-solid' : 'secondary'" > {{ spec.name }} diff --git a/web/projects/ui/src/app/routes/portal/routes/service/components/action.component.ts b/web/projects/ui/src/app/routes/portal/routes/service/components/action.component.ts index 5861b0fd0..fe6e30bec 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/components/action.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/components/action.component.ts @@ -1,5 +1,6 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core' import { TuiSvgModule } from '@taiga-ui/core' +import { TuiIconModule } from '@taiga-ui/experimental' interface ActionItem { readonly icon: string @@ -10,7 +11,7 @@ interface ActionItem { @Component({ selector: '[action]', template: ` - +
{{ action.name }}
{{ action.description }}
@@ -18,7 +19,7 @@ interface ActionItem { `, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [TuiSvgModule], + imports: [TuiIconModule], }) export class ServiceActionComponent { @Input({ required: true }) diff --git a/web/projects/ui/src/app/routes/portal/routes/service/components/actions.component.ts b/web/projects/ui/src/app/routes/portal/routes/service/components/actions.component.ts index 14889dcad..696c46620 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/components/actions.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/components/actions.component.ts @@ -4,13 +4,16 @@ import { inject, Input, } from '@angular/core' +import { Manifest } from '@startos' import { tuiPure } from '@taiga-ui/cdk' -import { TuiButtonModule } from '@taiga-ui/experimental' +import { + TuiButtonModule, + tuiButtonOptionsProvider, +} from '@taiga-ui/experimental' import { DependencyInfo } from 'src/app/routes/portal/routes/service/types/dependency-info' import { ActionsService } from 'src/app/services/actions.service' import { PackageDataEntry } from 'src/app/services/patch-db/data-model' import { getManifest } from 'src/app/utils/get-package-data' -import { Manifest } from '../../../../../../../../../../core/startos/bindings/Manifest' @Component({ selector: 'service-actions', @@ -18,7 +21,7 @@ import { Manifest } from '../../../../../../../../../../core/startos/bindings/Ma @if (pkg.status.main.status === 'running') { } `, - styles: [':host { display: flex; gap: 1rem }'], + styles: [ + ` + :host { + display: flex; + flex-wrap: wrap; + gap: 1rem; + padding-bottom: 1rem; + } + `, + ], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [TuiButtonModule], + providers: [tuiButtonOptionsProvider({ size: 's' })], }) export class ServiceActionsComponent { @Input({ required: true }) diff --git a/web/projects/ui/src/app/routes/portal/routes/service/components/additional.component.ts b/web/projects/ui/src/app/routes/portal/routes/service/components/additional.component.ts deleted file mode 100644 index 8678b9cc0..000000000 --- a/web/projects/ui/src/app/routes/portal/routes/service/components/additional.component.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { CommonModule } from '@angular/common' -import { ChangeDetectionStrategy, Component, Input } from '@angular/core' -import { PackageDataEntry } from 'src/app/services/patch-db/data-model' -import { ToAdditionalPipe } from '../pipes/to-additional.pipe' -import { ServiceAdditionalItemComponent } from './additional-item.component' - -@Component({ - selector: 'service-additional', - template: ` -

Additional Info

- - - - - - - `, - changeDetection: ChangeDetectionStrategy.OnPush, - standalone: true, - imports: [CommonModule, ToAdditionalPipe, ServiceAdditionalItemComponent], -}) -export class ServiceAdditionalComponent { - @Input({ required: true }) - pkg!: PackageDataEntry -} 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 new file mode 100644 index 000000000..e36ec202b --- /dev/null +++ b/web/projects/ui/src/app/routes/portal/routes/service/components/backups.component.ts @@ -0,0 +1,51 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core' +import { RouterLink } from '@angular/router' +import { TuiButtonModule } from '@taiga-ui/experimental' + +@Component({ + selector: 'service-backups', + template: ` +
+ Last backup + 6 days ago +
+
+ Next backup + Not scheduled +
+
+ + Manage + +
+ `, + styles: ` + :host { + display: flex; + gap: 1rem; + flex-wrap: wrap; + white-space: nowrap; + + > :last-child { + min-width: 100%; + padding-bottom: 1rem; + } + + small { + display: block; + text-transform: uppercase; + color: var(--tui-text-02); + } + } + `, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [TuiButtonModule, RouterLink], +}) +export class ServiceBackupsComponent {} diff --git a/web/projects/ui/src/app/routes/portal/routes/service/components/dependencies.component.ts b/web/projects/ui/src/app/routes/portal/routes/service/components/dependencies.component.ts index d735d5398..554d3d94d 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/components/dependencies.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/components/dependencies.component.ts @@ -1,22 +1,26 @@ -import { CommonModule } from '@angular/common' import { ChangeDetectionStrategy, Component, Input } from '@angular/core' -import { ServiceDependencyComponent } from './dependency.component' import { DependencyInfo } from '../types/dependency-info' +import { ServiceDependencyComponent } from './dependency.component' @Component({ selector: 'service-dependencies', template: ` -

Dependencies

- + @for (dep of dependencies; track $index) { + + } + + @if (!dependencies.length) { + No dependencies + } `, + styles: ':host { display: block; min-height: var(--tui-height-s) }', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [CommonModule, ServiceDependencyComponent], + imports: [ServiceDependencyComponent], }) export class ServiceDependenciesComponent { @Input({ required: true }) diff --git a/web/projects/ui/src/app/routes/portal/routes/service/components/health-check.component.ts b/web/projects/ui/src/app/routes/portal/routes/service/components/health-check.component.ts index 8281301ba..0d08ff124 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/components/health-check.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/components/health-check.component.ts @@ -1,7 +1,7 @@ import { CommonModule } from '@angular/common' import { ChangeDetectionStrategy, Component, Input } from '@angular/core' +import { HealthCheckResult } from '@startos' import { TuiLoaderModule, TuiSvgModule } from '@taiga-ui/core' -import { HealthCheckResult } from '../../../../../../../../../../core/startos/bindings/HealthCheckResult' @Component({ selector: 'service-health-check', diff --git a/web/projects/ui/src/app/routes/portal/routes/service/components/health-checks.component.ts b/web/projects/ui/src/app/routes/portal/routes/service/components/health-checks.component.ts index 25cb8b769..78c0b4fb1 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/components/health-checks.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/components/health-checks.component.ts @@ -1,28 +1,33 @@ -import { CommonModule } from '@angular/common' +import { AsyncPipe } from '@angular/common' import { ChangeDetectionStrategy, Component, inject, Input, } from '@angular/core' +import { HealthCheckResult } from '@startos' +import { ServiceHealthCheckComponent } from 'src/app/routes/portal/routes/service/components/health-check.component' import { ConnectionService } from 'src/app/services/connection.service' -import { ServiceHealthCheckComponent } from './health-check.component' -import { HealthCheckResult } from '../../../../../../../../../../core/startos/bindings/HealthCheckResult' @Component({ selector: 'service-health-checks', template: ` -

Health Checks

- + @for (check of checks; track $index) { + + } + + @if (!checks.length) { + No health checks + } `, + styles: ':host { display: block; min-height: var(--tui-height-s) }', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [CommonModule, ServiceHealthCheckComponent], + imports: [AsyncPipe, ServiceHealthCheckComponent], }) export class ServiceHealthChecksComponent { @Input({ required: true }) diff --git a/web/projects/ui/src/app/routes/portal/routes/service/components/interface-list-item.component.ts b/web/projects/ui/src/app/routes/portal/routes/service/components/interface-list-item.component.ts index 230e213bb..0e52abd64 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/components/interface-list-item.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/components/interface-list-item.component.ts @@ -5,35 +5,60 @@ import { inject, Input, } from '@angular/core' -import { TuiSvgModule } from '@taiga-ui/core' -import { TuiButtonModule } from '@taiga-ui/experimental' +import { TuiLetModule } from '@taiga-ui/cdk' +import { TuiLoaderModule } from '@taiga-ui/core' +import { TuiButtonModule, TuiIconModule } from '@taiga-ui/experimental' +import { map, timer } from 'rxjs' import { ConfigService } from 'src/app/services/config.service' import { ExtendedInterfaceInfo } from '../pipes/interface-info.pipe' @Component({ selector: 'a[serviceInterfaceListItem]', template: ` - -
- {{ info.name }} -
{{ info.description }}
-
{{ info.typeDetail }}
-
- + + @if (check === null) { + + } @else if (check === '') { + + } @else { + + } +
+ {{ info.name }} +
{{ info.description }}
+ @if (check) { +
+ Health check failed: + {{ check }} +
+ } @else { +
{{ info.typeDetail }}
+ } +
+ @if (info.type === 'ui') { + + } +
`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [TuiButtonModule, CommonModule, TuiSvgModule], + imports: [ + CommonModule, + TuiButtonModule, + TuiLetModule, + TuiLoaderModule, + TuiIconModule, + ], }) export class ServiceInterfaceListItemComponent { private readonly config = inject(ConfigService) @@ -44,6 +69,11 @@ export class ServiceInterfaceListItemComponent { @Input() disabled = false + // TODO: Implement real health check + readonly healthCheck$ = timer(3000).pipe( + map(() => (Math.random() > 0.5 ? '' : 'You done f***d it up...')), + ) + get href(): string | null { return this.disabled ? null : this.config.launchableAddress(this.info) } diff --git a/web/projects/ui/src/app/routes/portal/routes/service/components/interface-list.component.ts b/web/projects/ui/src/app/routes/portal/routes/service/components/interface-list.component.ts index c83258c0b..acd13ec08 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/components/interface-list.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/components/interface-list.component.ts @@ -1,31 +1,25 @@ -import { NgForOf } from '@angular/common' import { ChangeDetectionStrategy, Component, Input } from '@angular/core' +import { RouterLink } from '@angular/router' +import { PackageDataEntry } from 'src/app/services/patch-db/data-model' import { PackageStatus } from 'src/app/services/pkg-status-rendering.service' import { InterfaceInfoPipe } from '../pipes/interface-info.pipe' import { ServiceInterfaceListItemComponent } from './interface-list-item.component' -import { RouterLink } from '@angular/router' -import { PackageDataEntry } from 'src/app/services/patch-db/data-model' @Component({ selector: 'service-interface-list', template: ` -

Service Interfaces

- + @for (info of pkg | interfaceInfo; track $index) { + + } `, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [ - NgForOf, - RouterLink, - InterfaceInfoPipe, - ServiceInterfaceListItemComponent, - ], + imports: [RouterLink, InterfaceInfoPipe, ServiceInterfaceListItemComponent], }) export class ServiceInterfaceListComponent { @Input({ required: true }) diff --git a/web/projects/ui/src/app/routes/portal/routes/service/components/menu-item.component.ts b/web/projects/ui/src/app/routes/portal/routes/service/components/menu-item.component.ts index 6f6503f6f..ed2cae576 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/components/menu-item.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/components/menu-item.component.ts @@ -1,23 +1,23 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core' -import { TuiSvgModule } from '@taiga-ui/core' +import { TuiIconModule } from '@taiga-ui/experimental' import { ServiceMenu } from '../pipes/to-menu.pipe' @Component({ selector: '[serviceMenuItem]', template: ` - +
{{ menu.name }}
{{ menu.description }} - +
- + `, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, - imports: [TuiSvgModule], + imports: [TuiIconModule], }) export class ServiceMenuItemComponent { @Input({ required: true, alias: 'serviceMenuItem' }) diff --git a/web/projects/ui/src/app/routes/portal/routes/service/components/menu.component.ts b/web/projects/ui/src/app/routes/portal/routes/service/components/menu.component.ts index e1fa250ae..aea62aefd 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/components/menu.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/components/menu.component.ts @@ -7,7 +7,6 @@ import { RouterLink } from '@angular/router' @Component({ selector: 'service-menu', template: ` -

Menu

@for (menu of pkg | toMenu; track $index) { @if (menu.routerLink) { + } @else { + + } + } + `, + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ToAdditionalPipe, ServiceAdditionalItemComponent], +}) +export class ServiceAdditionalModal { + readonly pkg = + inject>(POLYMORPHEUS_CONTEXT).data +} diff --git a/web/projects/ui/src/app/routes/portal/routes/service/pipes/interface-info.pipe.ts b/web/projects/ui/src/app/routes/portal/routes/service/pipes/interface-info.pipe.ts index ebca06b40..a525bf509 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/pipes/interface-info.pipe.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/pipes/interface-info.pipe.ts @@ -24,17 +24,17 @@ export class InterfaceInfoPipe implements PipeTransform { switch (val.type) { case 'ui': color = 'var(--tui-primary)' - icon = 'tuiIconMonitorLarge' + icon = 'tuiIconMonitor' typeDetail = 'User Interface (UI)' break case 'p2p': color = 'var(--tui-info-fill)' - icon = 'tuiIconUsersLarge' + icon = 'tuiIconUsers' typeDetail = 'Peer-To-Peer Interface (P2P)' break case 'api': color = 'var(--tui-support-09)' - icon = 'tuiIconTerminalLarge' + icon = 'tuiIconTerminal' typeDetail = 'Application Program Interface (API)' break } diff --git a/web/projects/ui/src/app/routes/portal/routes/service/pipes/to-additional.pipe.ts b/web/projects/ui/src/app/routes/portal/routes/service/pipes/to-additional.pipe.ts index 06689bcd2..6be7f245d 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/pipes/to-additional.pipe.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/pipes/to-additional.pipe.ts @@ -1,12 +1,12 @@ import { inject, Pipe, PipeTransform } from '@angular/core' +import { CopyService, MarkdownComponent } from '@start9labs/shared' +import { Manifest } from '@startos' import { TuiDialogService } from '@taiga-ui/core' import { PolymorpheusComponent } from '@tinkoff/ng-polymorpheus' -import { CopyService, MarkdownComponent } from '@start9labs/shared' import { from } from 'rxjs' -import { PackageDataEntry } from 'src/app/services/patch-db/data-model' import { ApiService } from 'src/app/services/api/embassy-api.service' +import { PackageDataEntry } from 'src/app/services/patch-db/data-model' import { getManifest } from 'src/app/utils/get-package-data' -import { Manifest } from '../../../../../../../../../../core/startos/bindings/Manifest' export const FALLBACK_URL = 'Not provided' diff --git a/web/projects/ui/src/app/routes/portal/routes/service/pipes/to-menu.pipe.ts b/web/projects/ui/src/app/routes/portal/routes/service/pipes/to-menu.pipe.ts index 7df1aa01d..be4bca698 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/pipes/to-menu.pipe.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/pipes/to-menu.pipe.ts @@ -1,20 +1,21 @@ import { inject, Pipe, PipeTransform } from '@angular/core' import { Params } from '@angular/router' import { MarkdownComponent } from '@start9labs/shared' +import { Manifest } from '@startos' import { TuiDialogService } from '@taiga-ui/core' import { PolymorpheusComponent } from '@tinkoff/ng-polymorpheus' import { from } from 'rxjs' import { - PackageConfigData, ConfigModal, + PackageConfigData, } from 'src/app/routes/portal/modals/config.component' +import { ServiceAdditionalModal } from 'src/app/routes/portal/routes/service/modals/additional.component' import { ApiService } from 'src/app/services/api/embassy-api.service' import { FormDialogService } from 'src/app/services/form-dialog.service' import { PackageDataEntry } from 'src/app/services/patch-db/data-model' import { ProxyService } from 'src/app/services/proxy.service' -import { ServicePropertiesModal } from '../modals/properties.component' import { getManifest } from 'src/app/utils/get-package-data' -import { Manifest } from '../../../../../../../../../../core/startos/bindings/Manifest' +import { ServicePropertiesModal } from 'src/app/routes/portal/routes/service/modals/properties.component' export interface ServiceMenu { icon: string @@ -40,19 +41,19 @@ export class ToMenuPipe implements PipeTransform { return [ { - icon: 'tuiIconListLarge', + icon: 'tuiIconList', name: 'Instructions', description: `Understand how to use ${manifest.title}`, action: () => this.showInstructions(manifest), }, { - icon: 'tuiIconSlidersLarge', + icon: 'tuiIconSliders', name: 'Config', description: `Customize ${manifest.title}`, action: () => this.openConfig(manifest), }, { - icon: 'tuiIconKeyLarge', + icon: 'tuiIconKey', name: 'Properties', description: `Runtime information, credentials, and other values of interest`, action: () => @@ -64,13 +65,13 @@ export class ToMenuPipe implements PipeTransform { .subscribe(), }, { - icon: 'tuiIconZapLarge', + icon: 'tuiIconZap', name: 'Actions', description: `Uninstall and other commands specific to ${manifest.title}`, routerLink: `actions`, }, { - icon: 'tuiIconShieldLarge', + icon: 'tuiIconShield', name: 'Outbound Proxy', description: `Proxy all outbound traffic from ${manifest.title}`, action: () => @@ -80,21 +81,33 @@ export class ToMenuPipe implements PipeTransform { ), }, { - icon: 'tuiIconFileTextLarge', + icon: 'tuiIconFileText', name: 'Logs', description: `Raw, unfiltered logs`, routerLink: 'logs', }, + { + icon: 'tuiIconInfo', + name: 'Additional Info', + description: `View package details`, + action: () => + this.dialogs + .open(new PolymorpheusComponent(ServiceAdditionalModal), { + label: `Additional Info`, + data: pkg, + }) + .subscribe(), + }, pkg.marketplaceUrl ? { - icon: 'tuiIconShoppingBagLarge', + icon: 'tuiIconShoppingBag', name: 'Marketplace Listing', description: `View ${manifest.title} on the Marketplace`, routerLink: `/portal/system/marketplace`, params: { url: pkg.marketplaceUrl, id: manifest.id }, } : { - icon: 'tuiIconShoppingBagLarge', + icon: 'tuiIconShoppingBag', name: 'Marketplace Listing', description: `This package was not installed from the marketplace`, }, diff --git a/web/projects/ui/src/app/routes/portal/routes/service/routes/actions.component.ts b/web/projects/ui/src/app/routes/portal/routes/service/routes/actions.component.ts index 4e1256203..af7080f62 100644 --- a/web/projects/ui/src/app/routes/portal/routes/service/routes/actions.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/service/routes/actions.component.ts @@ -50,7 +50,7 @@ import { getAllPackages, getManifest } from 'src/app/utils/get-package-data' [action]="{ name: action.name, description: action.description, - icon: 'tuiIconPlayCircleLarge' + icon: 'tuiIconPlayCircle' }" (click)="handleAction(action)" > @@ -75,7 +75,7 @@ export class ServiceActionsRoute { .pipe(filter(pkg => pkg.stateInfo.state === 'installed')) readonly action = { - icon: 'tuiIconTrash2Large', + icon: 'tuiIconTrash2', name: 'Uninstall', description: 'This will uninstall the service from StartOS and delete all data permanently.', 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 a1e4e7001..e67b1f531 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 @@ -2,8 +2,15 @@ import { CommonModule } from '@angular/common' import { ChangeDetectionStrategy, Component, inject } from '@angular/core' import { ActivatedRoute, NavigationExtras, Router } from '@angular/router' import { isEmptyObject } from '@start9labs/shared' +import { HealthCheckResult, MainStatus, Manifest } from '@startos' import { PatchDB } from 'patch-db-client' import { combineLatest, map, switchMap } from 'rxjs' +import { + ConfigModal, + PackageConfigData, +} from 'src/app/routes/portal/modals/config.component' +import { ServiceBackupsComponent } from 'src/app/routes/portal/routes/service/components/backups.component' +import { InstallingProgressPipe } from 'src/app/routes/portal/routes/service/pipes/install-progress.pipe' import { ConnectionService } from 'src/app/services/connection.service' import { DepErrorService, @@ -21,87 +28,122 @@ import { StatusRendering, } from 'src/app/services/pkg-status-rendering.service' import { DependentInfo } from 'src/app/types/dependent-info' +import { getManifest } from 'src/app/utils/get-package-data' import { ServiceActionsComponent } from '../components/actions.component' -import { ServiceAdditionalComponent } from '../components/additional.component' import { ServiceDependenciesComponent } from '../components/dependencies.component' import { ServiceHealthChecksComponent } from '../components/health-checks.component' import { ServiceInterfaceListComponent } from '../components/interface-list.component' import { ServiceMenuComponent } from '../components/menu.component' import { ServiceProgressComponent } from '../components/progress.component' import { ServiceStatusComponent } from '../components/status.component' -import { - PackageConfigData, - ConfigModal, -} from 'src/app/routes/portal/modals/config.component' import { DependencyInfo } from '../types/dependency-info' -import { getManifest } from 'src/app/utils/get-package-data' -import { InstallingProgressPipe } from 'src/app/routes/portal/routes/service/pipes/install-progress.pipe' -import { Manifest } from '../../../../../../../../../../core/startos/bindings/Manifest' -import { HealthCheckResult } from '../../../../../../../../../../core/startos/bindings/HealthCheckResult' -import { MainStatus } from '../../../../../../../../../../core/startos/bindings/MainStatus' @Component({ template: ` @if (service$ | async; as service) { -

Status

- - - @if ( - service.pkg.stateInfo.state === 'installing' || - service.pkg.stateInfo.state === 'updating' || - service.pkg.stateInfo.state === 'restoring' - ) { -

+

Status

+ - {{ phase.name }} -

- } @else { - @if ( - service.pkg.stateInfo.state === 'installed' && - service.status.primary !== 'backingUp' - ) { - @if (connected$ | async) { - - } + /> + @if (isInstalled(service) && (connected$ | async)) { + + } + + + @if (isInstalled(service)) { +
+

Backups

+ +
+ +
+

Metrics

+ TODO +
+ +
+

Menu

+ +
+ +
+
+

Health Checks

+ +
+ +
+

Dependencies

+ +
+
+ +
+

Service Interfaces

+
+ } - @if ( - service.status.primary === 'running' && (health$ | async); - as checks - ) { - - } - - @if (service.dependencies.length) { - - } - - - + @if (isInstalling(service.pkg.stateInfo.state)) { + @for ( + item of service.pkg.stateInfo.installingInfo?.progress?.phases; + track $index + ) { +

{{ item.name }}

} } } `, + styles: ` + :host { + display: grid; + grid-template-columns: repeat(12, 1fr); + flex-direction: column; + gap: 1rem; + margin: 1rem -1rem 0; + } + + :host-context(tui-root._mobile) { + display: flex; + } + + section { + display: flex; + flex-direction: column; + width: 100%; + padding: 1rem 1.5rem 0.5rem; + border-radius: 1rem; + background: var(--tui-clear); + box-shadow: inset 0 7rem 0 -4rem var(--tui-clear); + clip-path: polygon(0 1.5rem, 1.5rem 0, 100% 0, 100% 100%, 0 100%); + } + + h3 { + margin-bottom: 1.25rem; + } + + div { + display: flex; + flex-direction: column; + gap: inherit; + grid-column: span 4; + } + `, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [ @@ -113,7 +155,7 @@ import { MainStatus } from '../../../../../../../../../../core/startos/bindings/ ServiceHealthChecksComponent, ServiceDependenciesComponent, ServiceMenuComponent, - ServiceAdditionalComponent, + ServiceBackupsComponent, InstallingProgressPipe, ], }) @@ -134,13 +176,11 @@ export class ServiceRoute { this.depErrorService.getPkgDepErrors$(pkgId), ]), ), - map(([pkg, depErrors]) => { - return { - pkg, - dependencies: this.getDepInfo(pkg, depErrors), - status: renderPkgStatus(pkg, depErrors), - } - }), + map(([pkg, depErrors]) => ({ + pkg, + dependencies: this.getDepInfo(pkg, depErrors), + status: renderPkgStatus(pkg, depErrors), + })), ) readonly health$ = this.pkgId$.pipe( @@ -150,6 +190,16 @@ export class ServiceRoute { map(toHealthCheck), ) + isInstalling(state: string): boolean { + return ( + state === 'installing' || state === 'updating' || state === 'restoring' + ) + } + + isInstalled({ pkg, status }: any): boolean { + return pkg.stateInfo.state === 'installed' && status.primary !== 'backingUp' + } + getRendering({ primary }: PackageStatus): StatusRendering { return PrimaryRendering[primary] } diff --git a/web/projects/ui/src/app/routes/portal/routes/system/backups/modals/history.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/backups/modals/history.component.ts index 1a44c2322..a91bb1a7b 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/backups/modals/history.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/backups/modals/history.component.ts @@ -26,7 +26,7 @@ import { GetBackupIconPipe } from '../pipes/get-backup-icon.pipe' Past Events