Merge branch 'next/minor' of github.com:Start9Labs/start-os into rebase/feat/domains

This commit is contained in:
Matt Hill
2024-03-30 21:14:53 -06:00
191 changed files with 1789 additions and 1316 deletions

View File

@@ -1,4 +1,5 @@
import { Url } from '@start9labs/shared'
import { Manifest } from '../../../../core/startos/bindings/Manifest'
export type StoreURL = string
export type StoreName = string
@@ -42,35 +43,6 @@ export interface DependencyMetadata {
hidden: boolean
}
export interface Manifest {
id: string
title: string
version: string
gitHash?: string
description: {
short: string
long: string
}
replaces?: string[]
releaseNotes: string
license: string // name of license
wrapperRepo: Url
upstreamRepo: Url
supportSite: Url
marketingSite: Url
donationUrl: Url | null
alerts: {
install: string | null
uninstall: string | null
restore: string | null
start: string | null
stop: string | null
}
dependencies: Record<string, Dependency>
osVersion: string
hasConfig: boolean
}
export interface Dependency {
description: string | null
optional: boolean

View File

@@ -1,7 +1,7 @@
import { Pipe, PipeTransform } from '@angular/core'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
import { Manifest } from '@start9labs/marketplace'
import { getManifest } from 'src/app/util/get-package-data'
import { Manifest } from '../../../../../../../../core/startos/bindings/Manifest'
@Pipe({
name: 'toManifest',
@@ -11,4 +11,4 @@ export class ToManifestPipe implements PipeTransform {
transform(pkg: PackageDataEntry): Manifest {
return getManifest(pkg)
}
}
}

View File

@@ -5,20 +5,18 @@ import {
computed,
inject,
input,
Input,
} from '@angular/core'
import { TuiLetModule, tuiPure } from '@taiga-ui/cdk'
import { TuiLetModule } from '@taiga-ui/cdk'
import {
TuiButtonModule,
tuiButtonOptionsProvider,
} from '@taiga-ui/experimental'
import { map, Observable } from 'rxjs'
import { map } from 'rxjs'
import { UILaunchComponent } from 'src/app/apps/portal/routes/dashboard/ui.component'
import { ActionsService } from 'src/app/apps/portal/services/actions.service'
import { DepErrorService } from 'src/app/services/dep-error.service'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
import { getManifest } from 'src/app/util/get-package-data'
import { Manifest } from '@start9labs/marketplace'
@Component({
standalone: true,

View File

@@ -8,11 +8,7 @@ import { tuiPure } from '@taiga-ui/cdk'
import { TuiLoaderModule } from '@taiga-ui/core'
import { TuiIconModule } from '@taiga-ui/experimental'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
import {
HealthStatus,
PrimaryStatus,
renderPkgStatus,
} from 'src/app/services/pkg-status-rendering.service'
import { renderPkgStatus } from 'src/app/services/pkg-status-rendering.service'
import { InstallingProgressDisplayPipe } from '../service/pipes/install-progress.pipe'
@Component({
@@ -68,7 +64,7 @@ export class StatusComponent {
return (
!this.hasDepErrors && // no deps error
!!this.pkg.status.configured && // no config needed
status.health !== HealthStatus.Failure // no health issues
status.health !== 'failure' // no health issues
)
}
@@ -83,29 +79,29 @@ export class StatusComponent {
get status(): string {
if (this.pkg.stateInfo.installingInfo) {
return `Installing... ${this.pipe.transform(this.pkg.stateInfo.installingInfo.progress.overall)}`
return `Installing...${this.pipe.transform(this.pkg.stateInfo.installingInfo.progress.overall)}`
}
switch (this.getStatus(this.pkg).primary) {
case PrimaryStatus.Running:
case 'running':
return 'Running'
case PrimaryStatus.Stopped:
case 'stopped':
return 'Stopped'
case PrimaryStatus.NeedsConfig:
case 'needsConfig':
return 'Needs Config'
case PrimaryStatus.Updating:
case 'updating':
return 'Updating...'
case PrimaryStatus.Stopping:
case 'stopping':
return 'Stopping...'
case PrimaryStatus.Starting:
case 'starting':
return 'Starting...'
case PrimaryStatus.BackingUp:
case 'backingUp':
return 'Backing Up...'
case PrimaryStatus.Restarting:
case 'restarting':
return 'Restarting...'
case PrimaryStatus.Removing:
case 'removing':
return 'Removing...'
case PrimaryStatus.Restoring:
case 'restoring':
return 'Restoring...'
default:
return 'Unknown'
@@ -114,18 +110,20 @@ export class StatusComponent {
get color(): string {
switch (this.getStatus(this.pkg).primary) {
case PrimaryStatus.Running:
case 'running':
return 'var(--tui-success-fill)'
case PrimaryStatus.NeedsConfig:
case 'needsConfig':
return 'var(--tui-warning-fill)'
case PrimaryStatus.Updating:
case PrimaryStatus.Stopping:
case PrimaryStatus.Starting:
case PrimaryStatus.BackingUp:
case PrimaryStatus.Restarting:
case PrimaryStatus.Removing:
case PrimaryStatus.Restoring:
case 'installing':
case 'updating':
case 'stopping':
case 'starting':
case 'backingUp':
case 'restarting':
case 'removing':
case 'restoring':
return 'var(--tui-info-fill)'
// stopped
default:
return 'var(--tui-text-02)'
}

View File

@@ -9,10 +9,7 @@ import { tuiPure } from '@taiga-ui/cdk'
import { TuiDataListModule, TuiHostedDropdownModule } from '@taiga-ui/core'
import { TuiButtonModule } from '@taiga-ui/experimental'
import { ConfigService } from 'src/app/services/config.service'
import {
PackageDataEntry,
PackageMainStatus,
} from 'src/app/services/patch-db/data-model'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
@Component({
standalone: true,
@@ -73,7 +70,7 @@ export class UILaunchComponent {
}
get isRunning(): boolean {
return this.pkg.status.main.status === PackageMainStatus.Running
return this.pkg.status.main.status === 'running'
}
@tuiPure

View File

@@ -9,8 +9,8 @@ import { TuiButtonModule } from '@taiga-ui/experimental'
import { DependencyInfo } from 'src/app/apps/portal/routes/service/types/dependency-info'
import { ActionsService } from 'src/app/apps/portal/services/actions.service'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
import { Manifest } from '@start9labs/marketplace'
import { getManifest } from 'src/app/util/get-package-data'
import { Manifest } from '../../../../../../../../../../core/startos/bindings/Manifest'
@Component({
selector: 'service-actions',

View File

@@ -1,10 +1,7 @@
import { CommonModule } from '@angular/common'
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
import { TuiLoaderModule, TuiSvgModule } from '@taiga-ui/core'
import {
HealthCheckResult,
HealthResult,
} from 'src/app/services/patch-db/data-model'
import { HealthCheckResult } from '../../../../../../../../../../core/startos/bindings/HealthCheckResult'
@Component({
selector: 'service-health-check',
@@ -54,18 +51,14 @@ export class ServiceHealthCheckComponent {
get loading(): boolean {
const { result } = this.check
return (
!result ||
result === HealthResult.Starting ||
result === HealthResult.Loading
)
return !result || result === 'starting' || result === 'loading'
}
get icon(): string {
switch (this.check.result) {
case HealthResult.Success:
case 'success':
return 'tuiIconCheckLarge'
case HealthResult.Failure:
case 'failure':
return 'tuiIconAlertTriangleLarge'
default:
return 'tuiIconMinusLarge'
@@ -74,13 +67,14 @@ export class ServiceHealthCheckComponent {
get color(): string {
switch (this.check.result) {
case HealthResult.Success:
case 'success':
return 'var(--tui-success-fill)'
case HealthResult.Failure:
case 'failure':
return 'var(--tui-warning-fill)'
case HealthResult.Starting:
case HealthResult.Loading:
case 'starting':
case 'loading':
return 'var(--tui-primary)'
// disabled
default:
return 'var(--tui-text-02)'
}
@@ -92,13 +86,14 @@ export class ServiceHealthCheckComponent {
}
switch (this.check.result) {
case HealthResult.Starting:
case 'starting':
return 'Starting...'
case HealthResult.Success:
case 'success':
return `Success: ${this.check.message}`
case HealthResult.Loading:
case HealthResult.Failure:
case 'loading':
case 'failure':
return this.check.message
// disabled
default:
return this.check.result
}

View File

@@ -5,9 +5,9 @@ import {
inject,
Input,
} from '@angular/core'
import { HealthCheckResult } from 'src/app/services/patch-db/data-model'
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',

View File

@@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
import { TuiProgressModule } from '@taiga-ui/kit'
import { Progress } from 'src/app/services/patch-db/data-model'
import { InstallingProgressPipe } from '../pipes/install-progress.pipe'
import { Progress } from '../../../../../../../../../../core/startos/bindings/Progress'
@Component({
selector: '[progress]',

View File

@@ -1,5 +1,5 @@
import { Pipe, PipeTransform } from '@angular/core'
import { Progress } from '../../../../../services/patch-db/data-model'
import { Progress } from '../../../../../../../../../../core/startos/bindings/Progress'
@Pipe({
standalone: true,

View File

@@ -1,12 +1,12 @@
import { inject, Pipe, PipeTransform } from '@angular/core'
import { TuiDialogService } from '@taiga-ui/core'
import { PolymorpheusComponent } from '@tinkoff/ng-polymorpheus'
import { Manifest } from '@start9labs/marketplace'
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 { getManifest } from 'src/app/util/get-package-data'
import { Manifest } from '../../../../../../../../../../core/startos/bindings/Manifest'
export const FALLBACK_URL = 'Not provided'

View File

@@ -1,6 +1,5 @@
import { inject, Pipe, PipeTransform } from '@angular/core'
import { Params } from '@angular/router'
import { Manifest } from '@start9labs/marketplace'
import { MarkdownComponent } from '@start9labs/shared'
import { TuiDialogService } from '@taiga-ui/core'
import { PolymorpheusComponent } from '@tinkoff/ng-polymorpheus'
@@ -15,6 +14,7 @@ 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/util/get-package-data'
import { Manifest } from '../../../../../../../../../../core/startos/bindings/Manifest'
export interface ServiceMenu {
icon: string

View File

@@ -18,7 +18,6 @@ import { ApiService } from 'src/app/services/api/embassy-api.service'
import {
DataModel,
PackageDataEntry,
PackageState,
} from 'src/app/services/patch-db/data-model'
import { hasCurrentDeps } from 'src/app/util/has-deps'
import { FormDialogService } from 'src/app/services/form-dialog.service'
@@ -73,7 +72,7 @@ export class ServiceActionsRoute {
readonly pkg$ = this.patch
.watch$('packageData', this.id)
.pipe(filter(pkg => pkg.stateInfo.state === PackageState.Installed))
.pipe(filter(pkg => pkg.stateInfo.state === 'installed'))
readonly action = {
icon: 'tuiIconTrash2Large',

View File

@@ -1,21 +1,17 @@
import { CommonModule } from '@angular/common'
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { ActivatedRoute, NavigationExtras, Router } from '@angular/router'
import { Manifest } from '@start9labs/marketplace'
import { isEmptyObject } from '@start9labs/shared'
import { PatchDB } from 'patch-db-client'
import { combineLatest, map, switchMap } from 'rxjs'
import { ConnectionService } from 'src/app/services/connection.service'
import {
DependencyErrorType,
DepErrorService,
PkgDependencyErrors,
} from 'src/app/services/dep-error.service'
import { FormDialogService } from 'src/app/services/form-dialog.service'
import {
DataModel,
HealthCheckResult,
MainStatus,
PackageDataEntry,
} from 'src/app/services/patch-db/data-model'
import {
@@ -40,6 +36,9 @@ import {
import { DependencyInfo } from '../types/dependency-info'
import { getManifest } from 'src/app/util/get-package-data'
import { InstallingProgressPipe } from 'src/app/apps/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: `
@@ -72,7 +71,7 @@ import { InstallingProgressPipe } from 'src/app/apps/portal/routes/service/pipes
} @else {
@if (
service.pkg.stateInfo.state === 'installed' &&
service.status.primary !== 'backing-up'
service.status.primary !== 'backingUp'
) {
@if (connected$ | async) {
<service-actions
@@ -211,24 +210,24 @@ export class ServiceRoute {
let fixAction: (() => any) | null = null
if (depError) {
if (depError.type === DependencyErrorType.NotInstalled) {
if (depError.type === 'notInstalled') {
errorText = 'Not installed'
fixText = 'Install'
fixAction = () => this.fixDep(pkg, pkgManifest, 'install', depId)
} else if (depError.type === DependencyErrorType.IncorrectVersion) {
} else if (depError.type === 'incorrectVersion') {
errorText = 'Incorrect version'
fixText = 'Update'
fixAction = () => this.fixDep(pkg, pkgManifest, 'update', depId)
} else if (depError.type === DependencyErrorType.ConfigUnsatisfied) {
} else if (depError.type === 'configUnsatisfied') {
errorText = 'Config not satisfied'
fixText = 'Auto config'
fixAction = () => this.fixDep(pkg, pkgManifest, 'configure', depId)
} else if (depError.type === DependencyErrorType.NotRunning) {
} else if (depError.type === 'notRunning') {
errorText = 'Not running'
fixText = 'Start'
} else if (depError.type === DependencyErrorType.HealthChecksFailed) {
} else if (depError.type === 'healthChecksFailed') {
errorText = 'Required health check not passing'
} else if (depError.type === DependencyErrorType.Transitive) {
} else if (depError.type === 'transitive') {
errorText = 'Dependency has a dependency issue'
}
}

View File

@@ -16,7 +16,7 @@ import {
} from '@tinkoff/ng-polymorpheus'
import { PatchDB } from 'patch-db-client'
import { firstValueFrom, map } from 'rxjs'
import { DataModel, PackageState } from 'src/app/services/patch-db/data-model'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { getManifest } from 'src/app/util/get-package-data'
interface Package {
@@ -100,7 +100,7 @@ export class BackupsBackupModal {
id,
title,
icon: pkg.icon,
disabled: pkg.stateInfo.state !== PackageState.Installed,
disabled: pkg.stateInfo.state !== 'installed',
checked: false,
}
})

View File

@@ -24,7 +24,6 @@ import { firstValueFrom } from 'rxjs'
import {
DataModel,
PackageDataEntry,
PackageState,
} from 'src/app/services/patch-db/data-model'
import { ClientStorageService } from 'src/app/services/client-storage.service'
import { MarketplaceService } from 'src/app/services/marketplace.service'

View File

@@ -6,7 +6,6 @@ import {
inject,
} from '@angular/core'
import { RouterLink } from '@angular/router'
import { Manifest } from '@start9labs/marketplace'
import { tuiPure } from '@taiga-ui/cdk'
import { TuiSvgModule } from '@taiga-ui/core'
import { TuiLineClampModule } from '@taiga-ui/kit'
@@ -16,6 +15,7 @@ import { ServerNotification } from 'src/app/services/api/api.types'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { NotificationService } from '../../../services/notification.service'
import { toRouterLink } from '../../../utils/to-router-link'
import { Manifest } from '../../../../../../../../../../core/startos/bindings/Manifest'
@Component({
selector: '[notificationItem]',

View File

@@ -47,7 +47,8 @@ export class StartOsUiComponent {
addSsl: {
scheme: 'https',
preferredExternalPort: 443,
addXForwardedHeaders: null,
// @TODO is this alpn correct?
alpn: { specified: ['http/1.1', 'h2'] },
},
secure: {
ssl: false,

View File

@@ -1,4 +1,4 @@
import { Manifest, MarketplacePkg } from '@start9labs/marketplace'
import { MarketplacePkg } from '@start9labs/marketplace'
import cbor from 'cbor'
interface Positions {

View File

@@ -11,9 +11,9 @@ 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 { hasCurrentDeps } from 'src/app/util/has-deps'
import { Manifest } from '@start9labs/marketplace'
import { getAllPackages } from 'src/app/util/get-package-data'
import { PatchDB } from 'patch-db-client'
import { Manifest } from '../../../../../../../../core/startos/bindings/Manifest'
@Injectable({
providedIn: 'root',

View File

@@ -1,8 +1,6 @@
import {
InstalledState,
PackageDataEntry,
PackageMainStatus,
PackageState,
ServerStatusInfo,
} from 'src/app/services/patch-db/data-model'
import {
@@ -12,15 +10,12 @@ import {
ServerNotifications,
} from './api.types'
import { BTC_ICON, LND_ICON, PROXY_ICON } from './api-icons'
import {
DependencyMetadata,
Manifest,
MarketplacePkg,
} from '@start9labs/marketplace'
import { DependencyMetadata, MarketplacePkg } from '@start9labs/marketplace'
import { Log } from '@start9labs/shared'
import { configBuilderToSpec } from 'src/app/util/configBuilderToSpec'
import { CT } from '@start9labs/start-sdk'
import { CB } from '@start9labs/start-sdk'
import { Manifest } from '../../../../../../../core/startos/bindings/Manifest'
export module Mock {
export const ServerUpdated: ServerStatusInfo = {
@@ -83,16 +78,26 @@ export module Mock {
osVersion: '0.2.12',
dependencies: {},
hasConfig: true,
images: ['main'],
assets: [],
volumes: ['main'],
hardwareRequirements: {
device: {},
arch: null,
ram: null,
},
}
export const MockManifestLnd: Manifest = {
id: 'lnd',
title: 'Lightning Network Daemon',
version: '0.11.1',
gitHash: 'abcdefgh',
description: {
short: 'A bolt spec compliant client.',
long: 'More info about LND. More info about LND. More info about LND.',
},
replaces: ['banks', 'governments'],
releaseNotes: 'Dual funded channels!',
license: 'MIT',
wrapperRepo: 'https://github.com/start9labs/lnd-wrapper',
@@ -121,6 +126,14 @@ export module Mock {
},
},
hasConfig: true,
images: ['main'],
assets: [],
volumes: ['main'],
hardwareRequirements: {
device: {},
arch: null,
ram: null,
},
}
export const MockManifestBitcoinProxy: Manifest = {
@@ -153,7 +166,16 @@ export module Mock {
optional: false,
},
},
replaces: [],
hasConfig: false,
images: ['main'],
assets: [],
volumes: ['main'],
hardwareRequirements: {
device: {},
arch: null,
ram: null,
},
}
export const BitcoinDep: DependencyMetadata = {
@@ -1260,7 +1282,7 @@ export module Mock {
export const bitcoind: PackageDataEntry<InstalledState> = {
stateInfo: {
state: PackageState.Installed,
state: 'installed',
manifest: MockManifestBitcoind,
},
icon: '/assets/img/service-icons/bitcoind.svg',
@@ -1269,7 +1291,7 @@ export module Mock {
status: {
configured: true,
main: {
status: PackageMainStatus.Running,
status: 'running',
started: new Date().toISOString(),
health: {},
},
@@ -1293,9 +1315,10 @@ export module Mock {
scheme: 'http',
preferredExternalPort: 80,
addSsl: {
addXForwardedHeaders: false,
// addXForwardedHeaders: false,
preferredExternalPort: 443,
scheme: 'https',
alpn: { specified: ['http/1.1', 'h2'] },
},
secure: null,
},
@@ -1365,9 +1388,10 @@ export module Mock {
scheme: 'http',
preferredExternalPort: 80,
addSsl: {
addXForwardedHeaders: false,
// addXForwardedHeaders: false,
preferredExternalPort: 443,
scheme: 'https',
alpn: { specified: ['http/1.1'] },
},
secure: null,
},
@@ -1493,6 +1517,8 @@ export module Mock {
},
},
currentDependencies: {},
hosts: {},
storeExposedDependents: [],
marketplaceUrl: 'https://registry.start9.com/',
developerKey: 'developer-key',
outboundProxy: null,
@@ -1500,7 +1526,7 @@ export module Mock {
export const bitcoinProxy: PackageDataEntry<InstalledState> = {
stateInfo: {
state: PackageState.Installed,
state: 'installed',
manifest: MockManifestBitcoinProxy,
},
icon: '/assets/img/service-icons/btc-rpc-proxy.png',
@@ -1509,7 +1535,7 @@ export module Mock {
status: {
configured: false,
main: {
status: PackageMainStatus.Stopped,
status: 'stopped',
},
dependencyConfigErrors: {},
},
@@ -1530,9 +1556,10 @@ export module Mock {
scheme: 'http',
preferredExternalPort: 80,
addSsl: {
addXForwardedHeaders: false,
// addXForwardedHeaders: false,
preferredExternalPort: 443,
scheme: 'https',
alpn: { specified: ['http/1.1', 'h2'] },
},
secure: {
ssl: true,
@@ -1632,6 +1659,8 @@ export module Mock {
healthChecks: [],
},
},
hosts: {},
storeExposedDependents: [],
marketplaceUrl: 'https://registry.start9.com/',
developerKey: 'developer-key',
outboundProxy: null,
@@ -1639,7 +1668,7 @@ export module Mock {
export const lnd: PackageDataEntry<InstalledState> = {
stateInfo: {
state: PackageState.Installed,
state: 'installed',
manifest: MockManifestLnd,
},
icon: '/assets/img/service-icons/lnd.png',
@@ -1648,7 +1677,7 @@ export module Mock {
status: {
configured: true,
main: {
status: PackageMainStatus.Stopped,
status: 'stopped',
},
dependencyConfigErrors: {
'btc-rpc-proxy': 'Username not found',
@@ -1882,9 +1911,10 @@ export module Mock {
kind: 'exists',
registryUrl: 'https://community-registry.start9.com',
versionSpec: '>2.0.0', // @TODO
healthChecks: [],
},
},
hosts: {},
storeExposedDependents: [],
marketplaceUrl: 'https://registry.start9.com/',
developerKey: 'developer-key',
outboundProxy: null,

View File

@@ -1,10 +1,9 @@
import { Dump, Revision } from 'patch-db-client'
import { MarketplacePkg, StoreInfo, Manifest } from '@start9labs/marketplace'
import { MarketplacePkg, StoreInfo } from '@start9labs/marketplace'
import {
DataModel,
DomainInfo,
NetworkStrategy,
HealthCheckResult,
} from 'src/app/services/patch-db/data-model'
import {
StartOSDiskInfo,
@@ -15,6 +14,8 @@ import {
} from '@start9labs/shared'
import { CT } from '@start9labs/start-sdk'
import { config } from '@start9labs/start-sdk'
import { HealthCheckResult } from '../../../../../../../core/startos/bindings/HealthCheckResult'
import { Manifest } from '../../../../../../../core/startos/bindings/Manifest'
export module RR {
// DB
@@ -644,40 +645,29 @@ export type DependencyError =
| DependencyErrorHealthChecksFailed
| DependencyErrorTransitive
export enum DependencyErrorType {
NotInstalled = 'not-installed',
NotRunning = 'not-running',
IncorrectVersion = 'incorrect-version',
ConfigUnsatisfied = 'config-unsatisfied',
HealthChecksFailed = 'health-checks-failed',
InterfaceHealthChecksFailed = 'interface-health-checks-failed',
Transitive = 'transitive',
}
export interface DependencyErrorNotInstalled {
type: DependencyErrorType.NotInstalled
type: 'notInstalled'
}
export interface DependencyErrorNotRunning {
type: DependencyErrorType.NotRunning
type: 'notRunning'
}
export interface DependencyErrorIncorrectVersion {
type: DependencyErrorType.IncorrectVersion
type: 'incorrectVersion'
expected: string // version range
received: string // version
}
export interface DependencyErrorConfigUnsatisfied {
type: DependencyErrorType.ConfigUnsatisfied
error: string
type: 'configUnsatisfied'
}
export interface DependencyErrorHealthChecksFailed {
type: DependencyErrorType.HealthChecksFailed
type: 'healthChecksFailed'
check: HealthCheckResult
}
export interface DependencyErrorTransitive {
type: DependencyErrorType.Transitive
type: 'transitive'
}

View File

@@ -10,11 +10,8 @@ import {
} from 'patch-db-client'
import {
DataModel,
FullProgress,
InstallingState,
PackageDataEntry,
PackageMainStatus,
PackageState,
Proxy,
StateInfo,
UpdatingState,
@@ -39,6 +36,7 @@ import { WebSocketSubjectConfig } from 'rxjs/webSocket'
import { AuthService } from '../auth.service'
import { ConnectionService } from '../connection.service'
import { StoreInfo } from '@start9labs/marketplace'
import { FullProgress } from '../../../../../../../core/startos/bindings/FullProgress'
const PROGRESS: FullProgress = {
overall: {
@@ -864,7 +862,7 @@ export class MockApiService extends ApiService {
{
op: PatchOp.REPLACE,
path: appPath,
value: PackageMainStatus.BackingUp,
value: 'backingUp',
},
]
this.mockRevision(appPatch)
@@ -874,7 +872,7 @@ export class MockApiService extends ApiService {
this.mockRevision([
{
...appPatch[0],
value: PackageMainStatus.Stopped,
value: 'stopped',
},
])
this.mockRevision([
@@ -979,10 +977,10 @@ export class MockApiService extends ApiService {
...Mock.LocalPkgs[params.id],
stateInfo: {
// if installing
// state: PackageState.Installing,
// state: 'installing',
// if updating
state: PackageState.Updating,
state: 'updating',
manifest: mockPatchData.packageData[params.id].stateInfo.manifest!,
// both
@@ -1047,7 +1045,7 @@ export class MockApiService extends ApiService {
value: {
...Mock.LocalPkgs[id],
stateInfo: {
state: PackageState.Restoring,
state: 'restoring',
installingInfo: {
newManifest: Mock.LocalPkgs[id].stateInfo.manifest!,
progress: PROGRESS,
@@ -1090,7 +1088,7 @@ export class MockApiService extends ApiService {
{
op: PatchOp.REPLACE,
path: path + '/status',
value: PackageMainStatus.Running,
value: 'running',
},
{
op: PatchOp.REPLACE,
@@ -1105,7 +1103,7 @@ export class MockApiService extends ApiService {
{
op: PatchOp.REPLACE,
path: path + '/status',
value: PackageMainStatus.Starting,
value: 'starting',
},
]
@@ -1126,7 +1124,7 @@ export class MockApiService extends ApiService {
{
op: PatchOp.REPLACE,
path: path + '/status',
value: PackageMainStatus.Starting,
value: 'starting',
},
{
op: PatchOp.ADD,
@@ -1142,7 +1140,7 @@ export class MockApiService extends ApiService {
{
op: PatchOp.REPLACE,
path: path + '/status',
value: PackageMainStatus.Running,
value: 'running',
},
{
op: PatchOp.REMOVE,
@@ -1179,7 +1177,7 @@ export class MockApiService extends ApiService {
{
op: PatchOp.REPLACE,
path: path + '/status',
value: PackageMainStatus.Restarting,
value: 'restarting',
},
{
op: PatchOp.REPLACE,
@@ -1203,7 +1201,7 @@ export class MockApiService extends ApiService {
op: PatchOp.REPLACE,
path: path,
value: {
status: PackageMainStatus.Stopped,
status: 'stopped',
},
},
]
@@ -1215,7 +1213,7 @@ export class MockApiService extends ApiService {
op: PatchOp.REPLACE,
path: path,
value: {
status: PackageMainStatus.Stopping,
status: 'stopping',
timeout: '35s',
},
},
@@ -1245,7 +1243,7 @@ export class MockApiService extends ApiService {
{
op: PatchOp.REPLACE,
path: `/packageData/${params.id}/stateInfo/state`,
value: PackageState.Removing,
value: 'removing',
},
]
@@ -1397,7 +1395,7 @@ export class MockApiService extends ApiService {
op: PatchOp.REPLACE,
path: `/packageData/${id}/stateInfo`,
value: {
state: PackageState.Installed,
state: 'installed',
manifest: Mock.LocalPkgs[id].stateInfo.manifest,
},
},

View File

@@ -1,9 +1,4 @@
import {
DataModel,
HealthResult,
PackageMainStatus,
PackageState,
} from 'src/app/services/patch-db/data-model'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { Mock } from './api.fixures'
export const mockPatchData: DataModel = {
@@ -12,7 +7,6 @@ export const mockPatchData: DataModel = {
ackWelcome: '1.0.0',
theme: 'Dark',
desktop: ['lnd'],
widgets: [],
marketplace: {
selectedUrl: 'https://registry.start9.com/',
knownHosts: {
@@ -138,11 +132,13 @@ export const mockPatchData: DataModel = {
passwordHash:
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
platform: 'x86_64-nonfree',
arch: 'x86_64',
governor: 'performance',
},
packageData: {
bitcoind: {
stateInfo: {
state: PackageState.Installed,
state: 'installed',
manifest: {
...Mock.MockManifestBitcoind,
version: '0.20.0',
@@ -154,31 +150,33 @@ export const mockPatchData: DataModel = {
status: {
configured: true,
main: {
status: PackageMainStatus.Running,
status: 'running',
started: '2021-06-14T20:49:17.774Z',
health: {
'ephemeral-health-check': {
name: 'Ephemeral Health Check',
result: HealthResult.Starting,
result: 'starting',
message: null,
},
'chain-state': {
name: 'Chain State',
result: HealthResult.Loading,
result: 'loading',
message: 'Bitcoin is syncing from genesis',
},
'p2p-interface': {
name: 'P2P',
result: HealthResult.Success,
result: 'success',
message: 'Health check successful',
},
'rpc-interface': {
name: 'RPC',
result: HealthResult.Failure,
result: 'failure',
message: 'RPC interface unreachable.',
},
'unnecessary-health-check': {
name: 'Unnecessary Health Check',
result: HealthResult.Disabled,
result: 'disabled',
message: null,
},
},
},
@@ -202,9 +200,10 @@ export const mockPatchData: DataModel = {
scheme: 'http',
preferredExternalPort: 80,
addSsl: {
addXForwardedHeaders: false,
// addXForwardedHeaders: false,
preferredExternalPort: 443,
scheme: 'https',
alpn: { specified: ['http/1.1', 'h2'] },
},
secure: null,
},
@@ -274,9 +273,10 @@ export const mockPatchData: DataModel = {
scheme: 'http',
preferredExternalPort: 80,
addSsl: {
addXForwardedHeaders: false,
// addXForwardedHeaders: false,
preferredExternalPort: 443,
scheme: 'https',
alpn: { specified: ['http/1.1'] },
},
secure: null,
},
@@ -402,13 +402,15 @@ export const mockPatchData: DataModel = {
},
},
currentDependencies: {},
hosts: {},
storeExposedDependents: [],
marketplaceUrl: 'https://registry.start9.com/',
developerKey: 'developer-key',
outboundProxy: null,
},
lnd: {
stateInfo: {
state: PackageState.Installed,
state: 'installed',
manifest: {
...Mock.MockManifestLnd,
version: '0.11.0',
@@ -420,7 +422,7 @@ export const mockPatchData: DataModel = {
status: {
configured: true,
main: {
status: PackageMainStatus.Stopped,
status: 'stopped',
},
dependencyConfigErrors: {
'btc-rpc-proxy': 'This is a config unsatisfied error',
@@ -655,6 +657,8 @@ export const mockPatchData: DataModel = {
healthChecks: [],
},
},
hosts: {},
storeExposedDependents: [],
marketplaceUrl: 'https://registry.start9.com/',
developerKey: 'developer-key',
outboundProxy: null,

View File

@@ -2,11 +2,12 @@ import { DOCUMENT } from '@angular/common'
import { Inject, Injectable } from '@angular/core'
import { WorkspaceConfig } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import {
PackageDataEntry,
PackageMainStatus,
PackageState,
} from 'src/app/services/patch-db/data-model'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
import { PackageState } from '../../../../../../core/startos/bindings/PackageState'
import { MainStatus } from '../../../../../../core/startos/bindings/MainStatus'
import { ExportedOnionHostname } from '../../../../../../core/startos/bindings/ExportedOnionHostname'
import { ExportedIpHostname } from '../../../../../../core/startos/bindings/ExportedIpHostname'
import { ExportedHostnameInfo } from '../../../../../../core/startos/bindings/ExportedHostnameInfo'
const {
gitHash,
@@ -77,10 +78,11 @@ export class ConfigService {
return window.isSecureContext || this.isTor()
}
isLaunchable(state: PackageState, status: PackageMainStatus): boolean {
return (
state === PackageState.Installed && status === PackageMainStatus.Running
)
isLaunchable(
state: PackageState['state'],
status: MainStatus['status'],
): boolean {
return state === 'installed' && status === 'running'
}
/** ${scheme}://${username}@${host}:${externalPort}${suffix} */
@@ -95,31 +97,28 @@ export class ConfigService {
const url = new URL(`${scheme}://${username}placeholder${suffix}`)
if (host.kind === 'multi') {
const onionHostname = host.hostnames.find(
(h: any) => h.kind === 'onion',
) as T.HostnameInfoOnion
const onionHostname = host.hostnames.find(h => h.kind === 'onion')
?.hostname as ExportedOnionHostname
if (this.isTor() && onionHostname) {
url.hostname = onionHostname.hostname.value
url.hostname = onionHostname.value
} else {
const ipHostname = host.hostnames.find(
(h: any) => h.kind === 'ip',
) as T.HostnameInfoIp
const ipHostname = host.hostnames.find(h => h.kind === 'ip')
?.hostname as ExportedIpHostname
if (!ipHostname) return ''
url.hostname = this.hostname
url.port = String(
ipHostname.hostname.sslPort || ipHostname.hostname.port,
)
url.port = String(ipHostname.sslPort || ipHostname.port)
}
} else {
const hostname = host.hostname
throw new Error('unimplemented')
const hostname = {} as ExportedHostnameInfo // host.hostname
if (!hostname) return ''
if (this.isTor() && hostname.kind === 'onion') {
url.hostname = hostname.hostname.value
url.hostname = (hostname.hostname as ExportedOnionHostname).value
} else {
url.hostname = this.hostname
url.port = String(hostname.hostname.sslPort || hostname.hostname.port)

View File

@@ -4,15 +4,13 @@ import { distinctUntilChanged, map, shareReplay } from 'rxjs/operators'
import { PatchDB } from 'patch-db-client'
import {
DataModel,
HealthResult,
InstalledState,
PackageDataEntry,
PackageMainStatus,
PackageState,
} from './patch-db/data-model'
import * as deepEqual from 'fast-deep-equal'
import { Observable } from 'rxjs'
import { isInstalled } from '../util/get-package-data'
import { DependencyError } from './api/api.types'
export type AllDependencyErrors = Record<string, PkgDependencyErrors>
export type PkgDependencyErrors = Record<string, DependencyError | null>
@@ -82,9 +80,9 @@ export class DepErrorService {
const dep = pkgs[depId]
// not installed
if (!dep || dep.stateInfo.state !== PackageState.Installed) {
if (!dep || dep.stateInfo.state !== 'installed') {
return {
type: DependencyErrorType.NotInstalled,
type: 'notInstalled',
}
}
@@ -94,7 +92,7 @@ export class DepErrorService {
// incorrect version
if (!this.emver.satisfies(depManifest.version, versionSpec)) {
return {
type: DependencyErrorType.IncorrectVersion,
type: 'incorrectVersion',
expected: versionSpec,
received: depManifest.version,
}
@@ -103,28 +101,29 @@ export class DepErrorService {
// invalid config
if (Object.values(pkg.status.dependencyConfigErrors).some(err => !!err)) {
return {
type: DependencyErrorType.ConfigUnsatisfied,
type: 'configUnsatisfied',
}
}
const depStatus = dep.status.main.status
// not running
if (
depStatus !== PackageMainStatus.Running &&
depStatus !== PackageMainStatus.Starting
) {
if (depStatus !== 'running' && depStatus !== 'starting') {
return {
type: DependencyErrorType.NotRunning,
type: 'notRunning',
}
}
const currentDep = pkg.currentDependencies[depId]
// health check failure
if (depStatus === PackageMainStatus.Running) {
for (let id of pkg.currentDependencies[depId].healthChecks) {
if (dep.status.main.health[id]?.result !== HealthResult.Success) {
if (depStatus === 'running' && currentDep.kind === 'running') {
for (let id of currentDep.healthChecks) {
const check = dep.status.main.health[id]
if (check?.result !== 'success') {
return {
type: DependencyErrorType.HealthChecksFailed,
type: 'healthChecksFailed',
check,
}
}
}
@@ -137,7 +136,7 @@ export class DepErrorService {
if (transitiveError) {
return {
type: DependencyErrorType.Transitive,
type: 'transitive',
}
}
@@ -161,46 +160,3 @@ function dependencyDepth(
depth,
)
}
export type DependencyError =
| DependencyErrorNotInstalled
| DependencyErrorNotRunning
| DependencyErrorIncorrectVersion
| DependencyErrorConfigUnsatisfied
| DependencyErrorHealthChecksFailed
| DependencyErrorTransitive
export enum DependencyErrorType {
NotInstalled = 'notInstalled',
NotRunning = 'notRunning',
IncorrectVersion = 'incorrectVersion',
ConfigUnsatisfied = 'configUnsatisfied',
HealthChecksFailed = 'healthChecksFailed',
Transitive = 'transitive',
}
export interface DependencyErrorNotInstalled {
type: DependencyErrorType.NotInstalled
}
export interface DependencyErrorNotRunning {
type: DependencyErrorType.NotRunning
}
export interface DependencyErrorIncorrectVersion {
type: DependencyErrorType.IncorrectVersion
expected: string // version range
received: string // version
}
export interface DependencyErrorConfigUnsatisfied {
type: DependencyErrorType.ConfigUnsatisfied
}
export interface DependencyErrorHealthChecksFailed {
type: DependencyErrorType.HealthChecksFailed
}
export interface DependencyErrorTransitive {
type: DependencyErrorType.Transitive
}

View File

@@ -6,7 +6,6 @@ import {
MarketplacePkg,
StoreData,
StoreIdentity,
StoreIdentityWithData,
StoreInfo,
} from '@start9labs/marketplace'
import { PatchDB } from 'patch-db-client'

View File

@@ -1,16 +1,17 @@
import { BackupJob, ServerNotifications } from '../api/api.types'
import { Url } from '@start9labs/shared'
import { Manifest } from '@start9labs/marketplace'
import { T } from '@start9labs/start-sdk'
import { config } from '@start9labs/start-sdk'
import { PackageDataEntry as PDE } from '../../../../../../../core/startos/bindings/PackageDataEntry'
import { FullProgress } from '../../../../../../../core/startos/bindings/FullProgress'
import { Manifest } from '../../../../../../../core/startos/bindings/Manifest'
export interface DataModel {
serverInfo: ServerInfo
packageData: { [id: string]: PackageDataEntry }
export type DataModel = {
ui: UIData
serverInfo: ServerInfo
packageData: Record<string, PackageDataEntry>
}
export interface UIData {
export type UIData = {
name: string | null
ackWelcome: string // emver
marketplace: UIMarketplaceData
@@ -21,24 +22,10 @@ export interface UIData {
}
ackInstructions: Record<string, boolean>
theme: string
widgets: readonly Widget[]
desktop: readonly string[]
}
export interface Widget {
id: string
meta: {
name: string
width: number
height: number
mobileWidth: number
mobileHeight: number
}
url?: string
settings?: string
}
export interface UIMarketplaceData {
export type UIMarketplaceData = {
selectedUrl: string
knownHosts: {
'https://registry.start9.com/': UIStore
@@ -47,11 +34,11 @@ export interface UIMarketplaceData {
}
}
export interface UIStore {
export type UIStore = {
name?: string
}
export interface ServerInfo {
export type ServerInfo = {
id: string
version: string
country: string
@@ -70,6 +57,8 @@ export interface ServerInfo {
smtp: typeof config.constants.customSmtp.validator._TYPE
passwordHash: string
platform: string
arch: string
governor: string | null
}
export type NetworkInfo = {
@@ -129,14 +118,6 @@ export type Proxy = {
}
}
export interface IpInfo {
[iface: string]: {
wireless: boolean
ipv4: string | null
ipv6: string | null
}
}
export interface ServerStatusInfo {
currentBackup: null | {
job: BackupJob
@@ -148,16 +129,8 @@ export interface ServerStatusInfo {
shuttingDown: boolean
}
export type PackageDataEntry<T extends StateInfo = StateInfo> = {
export type PackageDataEntry<T extends StateInfo = StateInfo> = PDE & {
stateInfo: T
icon: Url
status: Status
actions: Record<string, T.ActionMetadata>
lastBackup: string | null
currentDependencies: Record<string, CurrentDependencyInfo>
serviceInterfaces: Record<string, T.ServiceInterfaceWithHostInfo>
marketplaceUrl: string | null
developerKey: string
installedAt: string
outboundProxy: string | null
}
@@ -165,142 +138,24 @@ export type PackageDataEntry<T extends StateInfo = StateInfo> = {
export type StateInfo = InstalledState | InstallingState | UpdatingState
export type InstalledState = {
state: PackageState.Installed | PackageState.Removing
state: 'installed' | 'removing'
manifest: Manifest
installingInfo?: undefined
}
export type InstallingState = {
state: PackageState.Installing | PackageState.Restoring
state: 'installing' | 'restoring'
installingInfo: InstallingInfo
manifest?: undefined
}
export type UpdatingState = {
state: PackageState.Updating
state: 'updating'
installingInfo: InstallingInfo
manifest: Manifest
}
export enum PackageState {
Installing = 'installing',
Installed = 'installed',
Updating = 'updating',
Removing = 'removing',
Restoring = 'restoring',
}
export interface CurrentDependencyInfo {
title: string
icon: string
kind: 'exists' | 'running'
registryUrl: string
versionSpec: string
healthChecks: string[] // array of health check IDs
}
export interface Status {
configured: boolean
main: MainStatus
dependencyConfigErrors: { [id: string]: string | null }
}
export type MainStatus =
| MainStatusStopped
| MainStatusStopping
| MainStatusStarting
| MainStatusRunning
| MainStatusBackingUp
| MainStatusRestarting
| MainStatusConfiguring
export interface MainStatusStopped {
status: PackageMainStatus.Stopped
}
export interface MainStatusStopping {
status: PackageMainStatus.Stopping
timeout: string
}
export interface MainStatusStarting {
status: PackageMainStatus.Starting
}
export interface MainStatusRunning {
status: PackageMainStatus.Running
started: string // UTC date string
health: Record<string, HealthCheckResult>
}
export interface MainStatusBackingUp {
status: PackageMainStatus.BackingUp
}
export interface MainStatusRestarting {
status: PackageMainStatus.Restarting
}
export interface MainStatusConfiguring {
status: PackageMainStatus.Configuring
}
export enum PackageMainStatus {
Starting = 'starting',
Running = 'running',
Stopping = 'stopping',
Stopped = 'stopped',
BackingUp = 'backing-up',
Restarting = 'restarting',
Configuring = 'configuring',
}
export type HealthCheckResult = { name: string } & (
| HealthCheckResultStarting
| HealthCheckResultLoading
| HealthCheckResultDisabled
| HealthCheckResultSuccess
| HealthCheckResultFailure
)
export enum HealthResult {
Starting = 'starting',
Loading = 'loading',
Disabled = 'disabled',
Success = 'success',
Failure = 'failure',
}
export interface HealthCheckResultStarting {
result: HealthResult.Starting
}
export interface HealthCheckResultDisabled {
result: HealthResult.Disabled
}
export interface HealthCheckResultSuccess {
result: HealthResult.Success
message: string
}
export interface HealthCheckResultLoading {
result: HealthResult.Loading
message: string
}
export interface HealthCheckResultFailure {
result: HealthResult.Failure
message: string
}
export type InstallingInfo = {
progress: FullProgress
newManifest: Manifest
}
export type FullProgress = {
overall: Progress
phases: { name: string; progress: Progress }[]
}
export type Progress = boolean | { done: number; total: number | null } // false means indeterminate. true means complete

View File

@@ -1,70 +1,65 @@
import {
PackageDataEntry,
PackageMainStatus,
PackageState,
Status,
} from 'src/app/services/patch-db/data-model'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
import { PkgDependencyErrors } from './dep-error.service'
import { Status } from '../../../../../../core/startos/bindings/Status'
import { T } from '@start9labs/start-sdk'
export interface PackageStatus {
primary: PrimaryStatus | PackageState | PackageMainStatus
primary: PrimaryStatus
dependency: DependencyStatus | null
health: HealthStatus | null
health: T.HealthStatus | null
}
export function renderPkgStatus(
pkg: PackageDataEntry,
depErrors: PkgDependencyErrors,
): PackageStatus {
let primary: PrimaryStatus | PackageState | PackageMainStatus
let primary: PrimaryStatus
let dependency: DependencyStatus | null = null
let health: HealthStatus | null = null
let health: T.HealthStatus | null = null
if (pkg.stateInfo.state === PackageState.Installed) {
primary = getPrimaryStatus(pkg.status)
if (pkg.stateInfo.state === 'installed') {
primary = getInstalledPrimaryStatus(pkg.status)
dependency = getDependencyStatus(depErrors)
health = getHealthStatus(pkg.status)
} else {
primary = pkg.stateInfo.state as string as PrimaryStatus
primary = pkg.stateInfo.state
}
return { primary, dependency, health }
}
function getPrimaryStatus(status: Status): PrimaryStatus | PackageMainStatus {
function getInstalledPrimaryStatus(status: Status): PrimaryStatus {
if (!status.configured) {
return PrimaryStatus.NeedsConfig
return 'needsConfig'
} else {
return status.main.status
}
}
function getDependencyStatus(depErrors: PkgDependencyErrors): DependencyStatus {
return Object.values(depErrors).some(err => !!err)
? DependencyStatus.Warning
: DependencyStatus.Satisfied
return Object.values(depErrors).some(err => !!err) ? 'warning' : 'satisfied'
}
function getHealthStatus(status: Status): HealthStatus | null {
if (status.main.status !== PackageMainStatus.Running || !status.main.health) {
function getHealthStatus(status: Status): T.HealthStatus | null {
if (status.main.status !== 'running' || !status.main.health) {
return null
}
const values = Object.values(status.main.health)
if (values.some(h => h.result === 'failure')) {
return HealthStatus.Failure
return 'failure'
}
if (values.some(h => h.result === 'loading')) {
return HealthStatus.Loading
return 'loading'
}
if (values.some(h => h.result === 'starting')) {
return HealthStatus.Starting
return 'starting'
}
return HealthStatus.Healthy
return 'success'
}
export interface StatusRendering {
@@ -73,101 +68,88 @@ export interface StatusRendering {
showDots?: boolean
}
export enum PrimaryStatus {
// state
Installing = 'installing',
Updating = 'updating',
Removing = 'removing',
Restoring = 'restoring',
// status
Starting = 'starting',
Running = 'running',
Stopping = 'stopping',
Restarting = 'restarting',
Stopped = 'stopped',
BackingUp = 'backing-up',
// config
NeedsConfig = 'needs-config',
}
export type PrimaryStatus =
| 'installing'
| 'updating'
| 'removing'
| 'restoring'
| 'starting'
| 'running'
| 'stopping'
| 'restarting'
| 'stopped'
| 'backingUp'
| 'needsConfig'
export enum DependencyStatus {
Warning = 'warning',
Satisfied = 'satisfied',
}
export type DependencyStatus = 'warning' | 'satisfied'
export enum HealthStatus {
Failure = 'failure',
Starting = 'starting',
Loading = 'loading',
Healthy = 'healthy',
}
export const PrimaryRendering: Record<string, StatusRendering> = {
[PrimaryStatus.Installing]: {
export const PrimaryRendering: Record<PrimaryStatus, StatusRendering> = {
installing: {
display: 'Installing',
color: 'primary',
showDots: true,
},
[PrimaryStatus.Updating]: {
updating: {
display: 'Updating',
color: 'primary',
showDots: true,
},
[PrimaryStatus.Removing]: {
removing: {
display: 'Removing',
color: 'danger',
showDots: true,
},
[PrimaryStatus.Restoring]: {
restoring: {
display: 'Restoring',
color: 'primary',
showDots: true,
},
[PrimaryStatus.Stopping]: {
stopping: {
display: 'Stopping',
color: 'dark-shade',
showDots: true,
},
[PrimaryStatus.Restarting]: {
restarting: {
display: 'Restarting',
color: 'tertiary',
showDots: true,
},
[PrimaryStatus.Stopped]: {
stopped: {
display: 'Stopped',
color: 'dark-shade',
showDots: false,
},
[PrimaryStatus.BackingUp]: {
backingUp: {
display: 'Backing Up',
color: 'primary',
showDots: true,
},
[PrimaryStatus.Starting]: {
starting: {
display: 'Starting',
color: 'primary',
showDots: true,
},
[PrimaryStatus.Running]: {
running: {
display: 'Running',
color: 'success',
showDots: false,
},
[PrimaryStatus.NeedsConfig]: {
needsConfig: {
display: 'Needs Config',
color: 'warning',
showDots: false,
},
}
export const DependencyRendering: Record<string, StatusRendering> = {
[DependencyStatus.Warning]: { display: 'Issue', color: 'warning' },
[DependencyStatus.Satisfied]: { display: 'Satisfied', color: 'success' },
export const DependencyRendering: Record<DependencyStatus, StatusRendering> = {
warning: { display: 'Issue', color: 'warning' },
satisfied: { display: 'Satisfied', color: 'success' },
}
export const HealthRendering: Record<string, StatusRendering> = {
[HealthStatus.Failure]: { display: 'Failure', color: 'danger' },
[HealthStatus.Starting]: { display: 'Starting', color: 'primary' },
[HealthStatus.Loading]: { display: 'Loading', color: 'primary' },
[HealthStatus.Healthy]: { display: 'Healthy', color: 'success' },
export const HealthRendering: Record<T.HealthStatus, StatusRendering> = {
failure: { display: 'Failure', color: 'danger' },
starting: { display: 'Starting', color: 'primary' },
loading: { display: 'Loading', color: 'primary' },
success: { display: 'Healthy', color: 'success' },
disabled: { display: 'Disabled', color: 'dark' },
}

View File

@@ -1,9 +1,5 @@
import { Subscription } from 'rxjs'
import {
PackageDataEntry,
PackageMainStatus,
PackageState,
} from '../services/patch-db/data-model'
import { PackageDataEntry } from '../services/patch-db/data-model'
import {
PrimaryStatus,
StatusRendering,
@@ -12,7 +8,7 @@ import {
export interface PkgInfo {
entry: PackageDataEntry
primaryRendering: StatusRendering
primaryStatus: PrimaryStatus | PackageState | PackageMainStatus
primaryStatus: PrimaryStatus
error: boolean
warning: boolean
transitioning: boolean

View File

@@ -4,11 +4,10 @@ import {
InstalledState,
InstallingState,
PackageDataEntry,
PackageState,
UpdatingState,
} from 'src/app/services/patch-db/data-model'
import { firstValueFrom } from 'rxjs'
import { Manifest } from '@start9labs/marketplace'
import { Manifest } from '../../../../../../core/startos/bindings/Manifest'
export async function getPackage(
patch: PatchDB<DataModel>,
@@ -32,29 +31,29 @@ export function getManifest(pkg: PackageDataEntry): Manifest {
export function isInstalled(
pkg: PackageDataEntry,
): pkg is PackageDataEntry<InstalledState> {
return pkg.stateInfo.state === PackageState.Installed
return pkg.stateInfo.state === 'installed'
}
export function isRemoving(
pkg: PackageDataEntry,
): pkg is PackageDataEntry<InstalledState> {
return pkg.stateInfo.state === PackageState.Removing
return pkg.stateInfo.state === 'removing'
}
export function isInstalling(
pkg: PackageDataEntry,
): pkg is PackageDataEntry<InstallingState> {
return pkg.stateInfo.state === PackageState.Installing
return pkg.stateInfo.state === 'installing'
}
export function isRestoring(
pkg: PackageDataEntry,
): pkg is PackageDataEntry<InstallingState> {
return pkg.stateInfo.state === PackageState.Restoring
return pkg.stateInfo.state === 'restoring'
}
export function isUpdating(
pkg: PackageDataEntry,
): pkg is PackageDataEntry<UpdatingState> {
return pkg.stateInfo.state === PackageState.Updating
return pkg.stateInfo.state === 'updating'
}

View File

@@ -1,9 +1,6 @@
import { PackageDataEntry } from '../services/patch-db/data-model'
import {
DependencyStatus,
HealthStatus,
PrimaryRendering,
PrimaryStatus,
renderPkgStatus,
} from '../services/pkg-status-rendering.service'
import { PkgInfo } from '../types/pkg-info'
@@ -20,13 +17,11 @@ export function getPackageInfo(
entry,
primaryRendering,
primaryStatus: statuses.primary,
error:
statuses.health === HealthStatus.Failure ||
statuses.dependency === DependencyStatus.Warning,
warning: statuses.primary === PrimaryStatus.NeedsConfig,
error: statuses.health === 'failure' || statuses.dependency === 'warning',
warning: statuses.primary === 'needsConfig',
transitioning:
primaryRendering.showDots ||
statuses.health === HealthStatus.Loading ||
statuses.health === HealthStatus.Starting,
statuses.health === 'loading' ||
statuses.health === 'starting',
}
}