mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
fix a few, more to go (#2869)
* fix a few, more to go * chore: comments (#2871) * chore: comments * chore: typo * chore: stricter typescript (#2872) * chore: comments * chore: stricter typescript --------- Co-authored-by: Matt Hill <MattDHill@users.noreply.github.com> * minor styling --------- Co-authored-by: Alex Inkin <alexander@inkin.ru>
This commit is contained in:
@@ -501,9 +501,9 @@ export class MockApiService extends ApiService {
|
||||
): Promise<GetPackageRes> {
|
||||
await pauseFor(2000)
|
||||
if (!versionRange || versionRange === '=*') {
|
||||
return Mock.RegistryPackages[id]
|
||||
return Mock.RegistryPackages[id]!
|
||||
} else {
|
||||
return Mock.OtherPackageVersions[id][versionRange]
|
||||
return Mock.OtherPackageVersions[id]![versionRange]!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -870,7 +870,7 @@ export class MockApiService extends ApiService {
|
||||
|
||||
this.mockRevision([
|
||||
{
|
||||
...appPatch[0],
|
||||
...appPatch[0]!,
|
||||
value: 'stopped',
|
||||
},
|
||||
])
|
||||
@@ -1055,18 +1055,18 @@ export class MockApiService extends ApiService {
|
||||
op: PatchOp.ADD,
|
||||
path: `/packageData/${params.id}`,
|
||||
value: {
|
||||
...Mock.LocalPkgs[params.id],
|
||||
...Mock.LocalPkgs[params.id]!,
|
||||
stateInfo: {
|
||||
// if installing
|
||||
// state: 'installing',
|
||||
|
||||
// if updating
|
||||
state: 'updating',
|
||||
manifest: mockPatchData.packageData[params.id].stateInfo.manifest!,
|
||||
manifest: mockPatchData.packageData[params.id]?.stateInfo.manifest!,
|
||||
|
||||
// both
|
||||
installingInfo: {
|
||||
newManifest: Mock.LocalPkgs[params.id].stateInfo.manifest,
|
||||
newManifest: Mock.LocalPkgs[params.id]?.stateInfo.manifest!,
|
||||
progress: PROGRESS,
|
||||
},
|
||||
},
|
||||
@@ -1123,11 +1123,11 @@ export class MockApiService extends ApiService {
|
||||
op: PatchOp.ADD,
|
||||
path: `/packageData/${id}`,
|
||||
value: {
|
||||
...Mock.LocalPkgs[id],
|
||||
...Mock.LocalPkgs[id]!,
|
||||
stateInfo: {
|
||||
state: 'restoring',
|
||||
installingInfo: {
|
||||
newManifest: Mock.LocalPkgs[id].stateInfo.manifest!,
|
||||
newManifest: Mock.LocalPkgs[id]?.stateInfo.manifest!,
|
||||
progress: PROGRESS,
|
||||
},
|
||||
},
|
||||
@@ -1640,7 +1640,7 @@ export class MockApiService extends ApiService {
|
||||
) {
|
||||
await pauseFor(2000)
|
||||
|
||||
progress.phases[i].progress = true
|
||||
progress.phases[i]!.progress = true
|
||||
|
||||
if (
|
||||
progress.overall &&
|
||||
@@ -1671,7 +1671,7 @@ export class MockApiService extends ApiService {
|
||||
if (phase.progress.done === phase.progress.total) {
|
||||
await pauseFor(250)
|
||||
|
||||
progress.phases[i].progress = true
|
||||
progress.phases[i]!.progress = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1777,7 +1777,7 @@ export class MockApiService extends ApiService {
|
||||
path: `/packageData/${id}/stateInfo`,
|
||||
value: {
|
||||
state: 'installed',
|
||||
manifest: Mock.LocalPkgs[id].stateInfo.manifest,
|
||||
manifest: Mock.LocalPkgs[id]?.stateInfo.manifest!,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
@@ -47,7 +47,8 @@ export class BadgeService {
|
||||
|
||||
return (
|
||||
!curr[id] ||
|
||||
(p.stateInfo.installingInfo && !curr[id].stateInfo.installingInfo)
|
||||
(p.stateInfo.installingInfo &&
|
||||
!curr[id]?.stateInfo.installingInfo)
|
||||
)
|
||||
}),
|
||||
),
|
||||
@@ -70,7 +71,7 @@ export class BadgeService {
|
||||
local[id] &&
|
||||
this.exver.compareExver(
|
||||
version,
|
||||
getManifest(local[id]).version,
|
||||
getManifest(local[id]!).version,
|
||||
) === 1
|
||||
? result.add(id)
|
||||
: result,
|
||||
|
||||
@@ -59,7 +59,7 @@ export class ConfigService {
|
||||
(this.hostname.startsWith('192.168.') ||
|
||||
this.hostname.startsWith('10.') ||
|
||||
(this.hostname.startsWith('172.') &&
|
||||
!![this.hostname.split('.').map(Number)[1]].filter(
|
||||
!![this.hostname.split('.').map(Number)[1] || NaN].filter(
|
||||
n => n >= 16 && n < 32,
|
||||
).length))
|
||||
}
|
||||
@@ -107,13 +107,14 @@ export class ConfigService {
|
||||
if (!host) return ''
|
||||
|
||||
let hostnameInfo = host.hostnameInfo[ui.addressInfo.internalPort]
|
||||
hostnameInfo = hostnameInfo.filter(
|
||||
h =>
|
||||
this.isLocalhost() ||
|
||||
h.kind !== 'ip' ||
|
||||
h.hostname.kind !== 'ipv6' ||
|
||||
!h.hostname.value.startsWith('fe80::'),
|
||||
)
|
||||
hostnameInfo =
|
||||
hostnameInfo?.filter(
|
||||
h =>
|
||||
this.isLocalhost() ||
|
||||
h.kind !== 'ip' ||
|
||||
h.hostname.kind !== 'ipv6' ||
|
||||
!h.hostname.value.startsWith('fe80::'),
|
||||
) || []
|
||||
if (this.isLocalhost()) {
|
||||
const local = hostnameInfo.find(
|
||||
h => h.kind === 'ip' && h.hostname.kind === 'local',
|
||||
|
||||
@@ -2,9 +2,16 @@ import { inject, Injectable } from '@angular/core'
|
||||
import { ErrorService, LoadingService } from '@start9labs/shared'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { TuiDialogOptions, TuiDialogService } from '@taiga-ui/core'
|
||||
import { TuiConfirmData, TUI_CONFIRM } from '@taiga-ui/kit'
|
||||
import { TUI_CONFIRM, TuiConfirmData } from '@taiga-ui/kit'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { defaultIfEmpty, filter, firstValueFrom } from 'rxjs'
|
||||
import {
|
||||
defaultIfEmpty,
|
||||
defer,
|
||||
filter,
|
||||
firstValueFrom,
|
||||
of,
|
||||
switchMap,
|
||||
} from 'rxjs'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { getAllPackages } from 'src/app/utils/get-package-data'
|
||||
@@ -20,53 +27,16 @@ export class ControlsService {
|
||||
private readonly api = inject(ApiService)
|
||||
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
|
||||
|
||||
async start(manifest: T.Manifest, unmet: boolean): Promise<void> {
|
||||
const deps = `${manifest.title} has unmet dependencies. It will not work as expected.`
|
||||
async start({ title, alerts, id }: T.Manifest, unmet: boolean) {
|
||||
const deps = `${title} has unmet dependencies. It will not work as expected.`
|
||||
|
||||
if (
|
||||
(!unmet || (await this.alert(deps))) &&
|
||||
(!manifest.alerts.start || (await this.alert(manifest.alerts.start)))
|
||||
(unmet && !(await this.alert(deps))) ||
|
||||
(alerts.start && !(await this.alert(alerts.start)))
|
||||
) {
|
||||
this.doStart(manifest.id)
|
||||
}
|
||||
}
|
||||
|
||||
async stop({ id, title, alerts }: T.Manifest): Promise<void> {
|
||||
let content = alerts.stop || ''
|
||||
|
||||
if (hasCurrentDeps(id, await getAllPackages(this.patch))) {
|
||||
const depMessage = `Services that depend on ${title} will no longer work properly and may crash`
|
||||
content = content ? `${content}.\n\n${depMessage}` : depMessage
|
||||
return
|
||||
}
|
||||
|
||||
if (content) {
|
||||
this.dialogs
|
||||
.open(TUI_CONFIRM, getOptions(content, 'Stop'))
|
||||
.pipe(filter(Boolean))
|
||||
.subscribe(() => this.doStop(id))
|
||||
} else {
|
||||
this.doStop(id)
|
||||
}
|
||||
}
|
||||
|
||||
async restart({ id, title }: T.Manifest): Promise<void> {
|
||||
if (hasCurrentDeps(id, await getAllPackages(this.patch))) {
|
||||
this.dialogs
|
||||
.open(
|
||||
TUI_CONFIRM,
|
||||
getOptions(
|
||||
`Services that depend on ${title} may temporarily experiences issues`,
|
||||
'Restart',
|
||||
),
|
||||
)
|
||||
.pipe(filter(Boolean))
|
||||
.subscribe(() => this.doRestart(id))
|
||||
} else {
|
||||
this.doRestart(id)
|
||||
}
|
||||
}
|
||||
|
||||
private async doStart(id: string): Promise<void> {
|
||||
const loader = this.loader.open(`Starting...`).subscribe()
|
||||
|
||||
try {
|
||||
@@ -78,28 +48,55 @@ export class ControlsService {
|
||||
}
|
||||
}
|
||||
|
||||
private async doStop(id: string): Promise<void> {
|
||||
const loader = this.loader.open(`Stopping...`).subscribe()
|
||||
async stop({ id, title, alerts }: T.Manifest) {
|
||||
const depMessage = `Services that depend on ${title} will no longer work properly and may crash`
|
||||
let content = alerts.stop || ''
|
||||
|
||||
try {
|
||||
await this.api.stopPackage({ id })
|
||||
} catch (e: any) {
|
||||
this.errorService.handleError(e)
|
||||
} finally {
|
||||
loader.unsubscribe()
|
||||
if (hasCurrentDeps(id, await getAllPackages(this.patch))) {
|
||||
content = content ? `${content}.\n\n${depMessage}` : depMessage
|
||||
}
|
||||
|
||||
defer(() =>
|
||||
content
|
||||
? this.dialogs
|
||||
.open(TUI_CONFIRM, getOptions(content, 'Stop'))
|
||||
.pipe(filter(Boolean))
|
||||
: of(null),
|
||||
).subscribe(async () => {
|
||||
const loader = this.loader.open(`Stopping...`).subscribe()
|
||||
|
||||
try {
|
||||
await this.api.stopPackage({ id })
|
||||
} catch (e: any) {
|
||||
this.errorService.handleError(e)
|
||||
} finally {
|
||||
loader.unsubscribe()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private async doRestart(id: string): Promise<void> {
|
||||
const loader = this.loader.open(`Restarting...`).subscribe()
|
||||
async restart({ id, title }: T.Manifest) {
|
||||
const packages = await getAllPackages(this.patch)
|
||||
const options = getOptions(
|
||||
`Services that depend on ${title} may temporarily experiences issues`,
|
||||
'Restart',
|
||||
)
|
||||
|
||||
try {
|
||||
await this.api.restartPackage({ id })
|
||||
} catch (e: any) {
|
||||
this.errorService.handleError(e)
|
||||
} finally {
|
||||
loader.unsubscribe()
|
||||
}
|
||||
defer(() =>
|
||||
hasCurrentDeps(id, packages)
|
||||
? this.dialogs.open(TUI_CONFIRM, options).pipe(filter(Boolean))
|
||||
: of(null),
|
||||
).subscribe(async () => {
|
||||
const loader = this.loader.open(`Restarting...`).subscribe()
|
||||
|
||||
try {
|
||||
await this.api.restartPackage({ id })
|
||||
} catch (e: any) {
|
||||
this.errorService.handleError(e)
|
||||
} finally {
|
||||
loader.unsubscribe()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private alert(content: string): Promise<boolean> {
|
||||
|
||||
@@ -60,7 +60,7 @@ export class DepErrorService {
|
||||
): PkgDependencyErrors {
|
||||
const pkg = pkgs[pkgId]
|
||||
|
||||
if (!isInstalled(pkg)) return {}
|
||||
if (!pkg || !isInstalled(pkg)) return {}
|
||||
|
||||
return currentDeps(pkgs, pkgId).reduce(
|
||||
(innerErrors, depId): PkgDependencyErrors => ({
|
||||
@@ -88,17 +88,14 @@ export class DepErrorService {
|
||||
|
||||
const currentDep = pkg.currentDependencies[depId]
|
||||
const depManifest = dep.stateInfo.manifest
|
||||
const expected = currentDep?.versionRange || ''
|
||||
|
||||
// incorrect version
|
||||
if (!this.exver.satisfies(depManifest.version, currentDep.versionRange)) {
|
||||
if (
|
||||
depManifest.satisfies.some(
|
||||
v => !this.exver.satisfies(v, currentDep.versionRange),
|
||||
)
|
||||
) {
|
||||
if (!this.exver.satisfies(depManifest.version, expected)) {
|
||||
if (depManifest.satisfies.some(v => !this.exver.satisfies(v, expected))) {
|
||||
return {
|
||||
expected,
|
||||
type: 'incorrectVersion',
|
||||
expected: currentDep.versionRange,
|
||||
received: depManifest.version,
|
||||
}
|
||||
}
|
||||
@@ -128,10 +125,10 @@ export class DepErrorService {
|
||||
}
|
||||
|
||||
// health check failure
|
||||
if (depStatus === 'running' && currentDep.kind === 'running') {
|
||||
if (depStatus === 'running' && currentDep?.kind === 'running') {
|
||||
for (let id of currentDep.healthChecks) {
|
||||
const check = dep.status.health[id]
|
||||
if (check?.result !== 'success') {
|
||||
if (check && check?.result !== 'success') {
|
||||
return {
|
||||
type: 'healthChecksFailed',
|
||||
check,
|
||||
@@ -142,7 +139,7 @@ export class DepErrorService {
|
||||
|
||||
// transitive
|
||||
const transitiveError = currentDeps(pkgs, depId).some(transitiveId =>
|
||||
Object.values(outerErrors[transitiveId]).some(err => !!err),
|
||||
Object.values(outerErrors[transitiveId] || {}).some(err => !!err),
|
||||
)
|
||||
|
||||
if (transitiveError) {
|
||||
|
||||
@@ -42,9 +42,12 @@ export class FormService {
|
||||
const selected = valid ? value?.selection : spec.default
|
||||
const selection = this.getUnionSelectSpec(spec, selected)
|
||||
const group = this.getFormGroup({ selection })
|
||||
const control = selected ? spec.variants[selected].spec : {}
|
||||
const control = selected ? spec.variants[selected]?.spec : {}
|
||||
|
||||
group.setControl('value', this.getFormGroup(control, [], value?.value))
|
||||
group.setControl(
|
||||
'value',
|
||||
this.getFormGroup(control || {}, [], value?.value),
|
||||
)
|
||||
|
||||
return group
|
||||
}
|
||||
@@ -410,7 +413,12 @@ function listObjEquals(
|
||||
if (!uniqueBy) {
|
||||
return false
|
||||
} else if (typeof uniqueBy === 'string') {
|
||||
return uniqueByEquals(spec.spec[uniqueBy], val1[uniqueBy], val2[uniqueBy])
|
||||
const uniqueBySpec = spec.spec[uniqueBy]
|
||||
|
||||
return (
|
||||
!!uniqueBySpec &&
|
||||
uniqueByEquals(uniqueBySpec, val1[uniqueBy], val2[uniqueBy])
|
||||
)
|
||||
} else if ('any' in uniqueBy) {
|
||||
for (let unique of uniqueBy.any) {
|
||||
if (listObjEquals(unique, spec, val1, val2)) {
|
||||
@@ -522,8 +530,12 @@ export function convertValuesRecursive(
|
||||
convertValuesRecursive(valueSpec.spec, group.get(key) as UntypedFormGroup)
|
||||
} else if (valueSpec.type === 'union') {
|
||||
const formGr = group.get(key) as UntypedFormGroup
|
||||
const spec = valueSpec.variants[formGr.controls['selection'].value].spec
|
||||
convertValuesRecursive(spec, formGr)
|
||||
const value = formGr.controls['selection']?.value
|
||||
const spec = !!value && valueSpec.variants[value]?.spec
|
||||
|
||||
if (spec) {
|
||||
convertValuesRecursive(spec, formGr)
|
||||
}
|
||||
} else if (valueSpec.type === 'list') {
|
||||
const formArr = group.get(key) as UntypedFormArray
|
||||
const { controls } = formArr
|
||||
|
||||
@@ -249,20 +249,23 @@ export class MarketplaceService {
|
||||
flavor: string | null,
|
||||
pkgInfo: GetPackageRes,
|
||||
): MarketplacePkg {
|
||||
version =
|
||||
const ver =
|
||||
version ||
|
||||
Object.keys(pkgInfo.best).find(v => this.exver.getFlavor(v) === flavor) ||
|
||||
null
|
||||
const best = ver && pkgInfo.best[ver]
|
||||
|
||||
return !version || !pkgInfo.best[version]
|
||||
? ({} as MarketplacePkg)
|
||||
: {
|
||||
id,
|
||||
version,
|
||||
flavor,
|
||||
...pkgInfo,
|
||||
...pkgInfo.best[version],
|
||||
}
|
||||
if (!best) {
|
||||
return {} as MarketplacePkg
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
flavor,
|
||||
version: ver || '',
|
||||
...pkgInfo,
|
||||
...best,
|
||||
}
|
||||
}
|
||||
|
||||
getRequestErrors$(): Observable<string[]> {
|
||||
|
||||
Reference in New Issue
Block a user