mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-02 05:23:14 +00:00
Feature/shared refactor (#1176)
* refactor: move most of the shared entities to @start8labs/shared library
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { PackageState } from '@start9labs/shared'
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import {
|
||||
DependencyErrorType,
|
||||
@@ -5,14 +6,13 @@ import {
|
||||
Manifest,
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import {
|
||||
Log,
|
||||
MarketplacePkg,
|
||||
Metric,
|
||||
NotificationLevel,
|
||||
RR,
|
||||
NotificationLevel,
|
||||
ServerNotifications,
|
||||
} from './api.types'
|
||||
|
||||
@@ -479,7 +479,7 @@ export module Mock {
|
||||
'As long as Bitcoin is pruned, LND needs Bitcoin Proxy to fetch block over the P2P network.',
|
||||
requirement: {
|
||||
type: 'opt-in',
|
||||
how: "To use Proxy's user management system, go to LND config and select Bitcoin Proxy under Bitcoin config.",
|
||||
how: `To use Proxy's user management system, go to LND config and select Bitcoin Proxy under Bitcoin config.`,
|
||||
},
|
||||
config: null,
|
||||
},
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { pauseFor } from '../../util/misc.util'
|
||||
import { InstallProgress, pauseFor } from '@start9labs/shared'
|
||||
import { ApiService } from './embassy-api.service'
|
||||
import { PatchOp, Update, Operation, RemoveOperation } from 'patch-db-client'
|
||||
import { PackageState } from '@start9labs/shared'
|
||||
import {
|
||||
DataModel,
|
||||
DependencyErrorType,
|
||||
InstallProgress,
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
ServerStatus,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { CifsBackupTarget, Log, RR, WithRevision } from './api.types'
|
||||
@@ -25,22 +24,22 @@ export class MockApiService extends ApiService {
|
||||
private readonly revertTime = 4000
|
||||
sequence: number
|
||||
|
||||
constructor (private readonly bootstrapper: LocalStorageBootstrap) {
|
||||
constructor(private readonly bootstrapper: LocalStorageBootstrap) {
|
||||
super()
|
||||
}
|
||||
|
||||
async getStatic (url: string): Promise<string> {
|
||||
async getStatic(url: string): Promise<string> {
|
||||
await pauseFor(2000)
|
||||
return markdown
|
||||
}
|
||||
|
||||
// db
|
||||
|
||||
async getRevisions (since: number): Promise<RR.GetRevisionsRes> {
|
||||
async getRevisions(since: number): Promise<RR.GetRevisionsRes> {
|
||||
return this.getDump()
|
||||
}
|
||||
|
||||
async getDump (): Promise<RR.GetDumpRes> {
|
||||
async getDump(): Promise<RR.GetDumpRes> {
|
||||
const cache = await this.bootstrapper.init()
|
||||
return {
|
||||
id: cache.sequence,
|
||||
@@ -49,7 +48,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async setDbValueRaw (params: RR.SetDBValueReq): Promise<RR.SetDBValueRes> {
|
||||
async setDbValueRaw(params: RR.SetDBValueReq): Promise<RR.SetDBValueRes> {
|
||||
await pauseFor(2000)
|
||||
const patch = [
|
||||
{
|
||||
@@ -63,7 +62,7 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// auth
|
||||
|
||||
async login (params: RR.LoginReq): Promise<RR.loginRes> {
|
||||
async login(params: RR.LoginReq): Promise<RR.loginRes> {
|
||||
await pauseFor(2000)
|
||||
|
||||
setTimeout(() => {
|
||||
@@ -73,24 +72,24 @@ export class MockApiService extends ApiService {
|
||||
return null
|
||||
}
|
||||
|
||||
async logout (params: RR.LogoutReq): Promise<RR.LogoutRes> {
|
||||
async logout(params: RR.LogoutReq): Promise<RR.LogoutRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async getSessions (params: RR.GetSessionsReq): Promise<RR.GetSessionsRes> {
|
||||
async getSessions(params: RR.GetSessionsReq): Promise<RR.GetSessionsRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.Sessions
|
||||
}
|
||||
|
||||
async killSessions (params: RR.KillSessionsReq): Promise<RR.KillSessionsRes> {
|
||||
async killSessions(params: RR.KillSessionsReq): Promise<RR.KillSessionsRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
// server
|
||||
|
||||
async getServerLogs (
|
||||
async getServerLogs(
|
||||
params: RR.GetServerLogsReq,
|
||||
): Promise<RR.GetServerLogsRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -112,21 +111,21 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async getServerMetrics (
|
||||
async getServerMetrics(
|
||||
params: RR.GetServerMetricsReq,
|
||||
): Promise<RR.GetServerMetricsRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.getServerMetrics()
|
||||
}
|
||||
|
||||
async getPkgMetrics (
|
||||
async getPkgMetrics(
|
||||
params: RR.GetServerMetricsReq,
|
||||
): Promise<RR.GetPackageMetricsRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.getAppMetrics()
|
||||
}
|
||||
|
||||
async updateServerRaw (
|
||||
async updateServerRaw(
|
||||
params: RR.UpdateServerReq,
|
||||
): Promise<RR.UpdateServerRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -150,21 +149,21 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch, 'updating')
|
||||
}
|
||||
|
||||
async restartServer (
|
||||
async restartServer(
|
||||
params: RR.RestartServerReq,
|
||||
): Promise<RR.RestartServerRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async shutdownServer (
|
||||
async shutdownServer(
|
||||
params: RR.ShutdownServerReq,
|
||||
): Promise<RR.ShutdownServerRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async systemRebuild (
|
||||
async systemRebuild(
|
||||
params: RR.RestartServerReq,
|
||||
): Promise<RR.RestartServerRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -173,7 +172,7 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// marketplace URLs
|
||||
|
||||
async marketplaceProxy (path: string, params: {}, url: string): Promise<any> {
|
||||
async marketplaceProxy(path: string, params: {}, url: string): Promise<any> {
|
||||
await pauseFor(2000)
|
||||
|
||||
if (path === '/package/v0/info') {
|
||||
@@ -196,7 +195,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async getEos (
|
||||
async getEos(
|
||||
params: RR.GetMarketplaceEOSReq,
|
||||
): Promise<RR.GetMarketplaceEOSRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -211,7 +210,7 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// notification
|
||||
|
||||
async getNotificationsRaw (
|
||||
async getNotificationsRaw(
|
||||
params: RR.GetNotificationsReq,
|
||||
): Promise<RR.GetNotificationsRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -226,14 +225,14 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch, Mock.Notifications)
|
||||
}
|
||||
|
||||
async deleteNotification (
|
||||
async deleteNotification(
|
||||
params: RR.DeleteNotificationReq,
|
||||
): Promise<RR.DeleteNotificationRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async deleteAllNotifications (
|
||||
async deleteAllNotifications(
|
||||
params: RR.DeleteAllNotificationsReq,
|
||||
): Promise<RR.DeleteAllNotificationsRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -242,60 +241,60 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// wifi
|
||||
|
||||
async getWifi (params: RR.GetWifiReq): Promise<RR.GetWifiRes> {
|
||||
async getWifi(params: RR.GetWifiReq): Promise<RR.GetWifiRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.Wifi
|
||||
}
|
||||
|
||||
async setWifiCountry (
|
||||
async setWifiCountry(
|
||||
params: RR.SetWifiCountryReq,
|
||||
): Promise<RR.SetWifiCountryRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async addWifi (params: RR.AddWifiReq): Promise<RR.AddWifiRes> {
|
||||
async addWifi(params: RR.AddWifiReq): Promise<RR.AddWifiRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async connectWifi (params: RR.ConnectWifiReq): Promise<RR.ConnectWifiRes> {
|
||||
async connectWifi(params: RR.ConnectWifiReq): Promise<RR.ConnectWifiRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async deleteWifi (params: RR.DeleteWifiReq): Promise<RR.DeleteWifiRes> {
|
||||
async deleteWifi(params: RR.DeleteWifiReq): Promise<RR.DeleteWifiRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
// ssh
|
||||
|
||||
async getSshKeys (params: RR.GetSSHKeysReq): Promise<RR.GetSSHKeysRes> {
|
||||
async getSshKeys(params: RR.GetSSHKeysReq): Promise<RR.GetSSHKeysRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.SshKeys
|
||||
}
|
||||
|
||||
async addSshKey (params: RR.AddSSHKeyReq): Promise<RR.AddSSHKeyRes> {
|
||||
async addSshKey(params: RR.AddSSHKeyReq): Promise<RR.AddSSHKeyRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.SshKey
|
||||
}
|
||||
|
||||
async deleteSshKey (params: RR.DeleteSSHKeyReq): Promise<RR.DeleteSSHKeyRes> {
|
||||
async deleteSshKey(params: RR.DeleteSSHKeyReq): Promise<RR.DeleteSSHKeyRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
// backup
|
||||
|
||||
async getBackupTargets (
|
||||
async getBackupTargets(
|
||||
params: RR.GetBackupTargetsReq,
|
||||
): Promise<RR.GetBackupTargetsRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.BackupTargets
|
||||
}
|
||||
|
||||
async addBackupTarget (
|
||||
async addBackupTarget(
|
||||
params: RR.AddBackupTargetReq,
|
||||
): Promise<RR.AddBackupTargetRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -312,7 +311,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async updateBackupTarget (
|
||||
async updateBackupTarget(
|
||||
params: RR.UpdateBackupTargetReq,
|
||||
): Promise<RR.UpdateBackupTargetRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -327,21 +326,21 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async removeBackupTarget (
|
||||
async removeBackupTarget(
|
||||
params: RR.RemoveBackupTargetReq,
|
||||
): Promise<RR.RemoveBackupTargetRes> {
|
||||
await pauseFor(2000)
|
||||
return null
|
||||
}
|
||||
|
||||
async getBackupInfo (
|
||||
async getBackupInfo(
|
||||
params: RR.GetBackupInfoReq,
|
||||
): Promise<RR.GetBackupInfoRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.BackupInfo
|
||||
}
|
||||
|
||||
async createBackupRaw (
|
||||
async createBackupRaw(
|
||||
params: RR.CreateBackupReq,
|
||||
): Promise<RR.CreateBackupRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -392,14 +391,14 @@ export class MockApiService extends ApiService {
|
||||
|
||||
// package
|
||||
|
||||
async getPackageProperties (
|
||||
async getPackageProperties(
|
||||
params: RR.GetPackagePropertiesReq,
|
||||
): Promise<RR.GetPackagePropertiesRes<2>['data']> {
|
||||
await pauseFor(2000)
|
||||
return parsePropertiesPermissive(Mock.PackageProperties)
|
||||
}
|
||||
|
||||
async getPackageLogs (
|
||||
async getPackageLogs(
|
||||
params: RR.GetPackageLogsReq,
|
||||
): Promise<RR.GetPackageLogsRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -421,7 +420,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async installPackageRaw (
|
||||
async installPackageRaw(
|
||||
params: RR.InstallPackageReq,
|
||||
): Promise<RR.InstallPackageRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -456,14 +455,14 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async dryUpdatePackage (
|
||||
async dryUpdatePackage(
|
||||
params: RR.DryUpdatePackageReq,
|
||||
): Promise<RR.DryUpdatePackageRes> {
|
||||
await pauseFor(2000)
|
||||
return {}
|
||||
}
|
||||
|
||||
async getPackageConfig (
|
||||
async getPackageConfig(
|
||||
params: RR.GetPackageConfigReq,
|
||||
): Promise<RR.GetPackageConfigRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -473,14 +472,14 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async drySetPackageConfig (
|
||||
async drySetPackageConfig(
|
||||
params: RR.DrySetPackageConfigReq,
|
||||
): Promise<RR.DrySetPackageConfigRes> {
|
||||
await pauseFor(2000)
|
||||
return {}
|
||||
}
|
||||
|
||||
async setPackageConfigRaw (
|
||||
async setPackageConfigRaw(
|
||||
params: RR.SetPackageConfigReq,
|
||||
): Promise<RR.SetPackageConfigRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -494,7 +493,7 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async restorePackagesRaw (
|
||||
async restorePackagesRaw(
|
||||
params: RR.RestorePackagesReq,
|
||||
): Promise<RR.RestorePackagesRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -530,14 +529,14 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async executePackageAction (
|
||||
async executePackageAction(
|
||||
params: RR.ExecutePackageActionReq,
|
||||
): Promise<RR.ExecutePackageActionRes> {
|
||||
await pauseFor(2000)
|
||||
return Mock.ActionResponse
|
||||
}
|
||||
|
||||
async startPackageRaw (
|
||||
async startPackageRaw(
|
||||
params: RR.StartPackageReq,
|
||||
): Promise<RR.StartPackageRes> {
|
||||
const path = `/package-data/${params.id}/installed/status/main`
|
||||
@@ -616,7 +615,7 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(originalPatch)
|
||||
}
|
||||
|
||||
async dryStopPackage (
|
||||
async dryStopPackage(
|
||||
params: RR.DryStopPackageReq,
|
||||
): Promise<RR.DryStopPackageRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -630,7 +629,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
async stopPackageRaw (params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
|
||||
async stopPackageRaw(params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
|
||||
await pauseFor(2000)
|
||||
const path = `/package-data/${params.id}/installed/status/main`
|
||||
|
||||
@@ -661,14 +660,14 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async dryUninstallPackage (
|
||||
async dryUninstallPackage(
|
||||
params: RR.DryUninstallPackageReq,
|
||||
): Promise<RR.DryUninstallPackageRes> {
|
||||
await pauseFor(2000)
|
||||
return {}
|
||||
}
|
||||
|
||||
async uninstallPackageRaw (
|
||||
async uninstallPackageRaw(
|
||||
params: RR.UninstallPackageReq,
|
||||
): Promise<RR.UninstallPackageRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -694,7 +693,7 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async deleteRecoveredPackageRaw (
|
||||
async deleteRecoveredPackageRaw(
|
||||
params: RR.DeleteRecoveredPackageReq,
|
||||
): Promise<RR.DeleteRecoveredPackageRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -707,7 +706,7 @@ export class MockApiService extends ApiService {
|
||||
return this.withRevision(patch)
|
||||
}
|
||||
|
||||
async dryConfigureDependency (
|
||||
async dryConfigureDependency(
|
||||
params: RR.DryConfigureDependencyReq,
|
||||
): Promise<RR.DryConfigureDependencyRes> {
|
||||
await pauseFor(2000)
|
||||
@@ -718,7 +717,7 @@ export class MockApiService extends ApiService {
|
||||
}
|
||||
}
|
||||
|
||||
private async updateProgress (
|
||||
private async updateProgress(
|
||||
id: string,
|
||||
initialProgress: InstallProgress,
|
||||
): Promise<void> {
|
||||
@@ -764,7 +763,7 @@ export class MockApiService extends ApiService {
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
private async updateOSProgress (size: number) {
|
||||
private async updateOSProgress(size: number) {
|
||||
let downloaded = 0
|
||||
while (downloaded < size) {
|
||||
await pauseFor(250)
|
||||
@@ -814,7 +813,7 @@ export class MockApiService extends ApiService {
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
private async updateMock (patch: Operation[]): Promise<void> {
|
||||
private async updateMock(patch: Operation[]): Promise<void> {
|
||||
if (!this.sequence) {
|
||||
const { sequence } = await this.bootstrapper.init()
|
||||
this.sequence = sequence
|
||||
@@ -827,7 +826,7 @@ export class MockApiService extends ApiService {
|
||||
this.mockPatch$.next(revision)
|
||||
}
|
||||
|
||||
private async withRevision<T> (
|
||||
private async withRevision<T>(
|
||||
patch: Operation[],
|
||||
response: T = null,
|
||||
): Promise<WithRevision<T>> {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { PackageState } from '@start9labs/shared'
|
||||
import {
|
||||
DataModel,
|
||||
DependencyErrorType,
|
||||
@@ -5,13 +6,11 @@ import {
|
||||
HealthResult,
|
||||
Manifest,
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
ServerStatus,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
|
||||
export const mockPatchData: DataModel = {
|
||||
ui: {
|
||||
name: "Matt's Embassy",
|
||||
name: `Matt's Embassy`,
|
||||
'auto-check-updates': true,
|
||||
'pkg-order': [],
|
||||
'ack-welcome': '1.0.0',
|
||||
@@ -86,13 +85,11 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
'ephemeral-health-check': {
|
||||
name: 'Ephemeral Health Check',
|
||||
description:
|
||||
"Checks to see if your new user registrations are on. If they are but you're not expecting any new user signups, you should disable this in Config, as anyone who knows your onion URL can create accounts on your server.",
|
||||
description: `Checks to see if your new user registrations are on. If they are but you're not expecting any new user signups, you should disable this in Config, as anyone who knows your onion URL can create accounts on your server.`,
|
||||
},
|
||||
'p2p-interface': {
|
||||
name: 'P2P Interface',
|
||||
description:
|
||||
"Checks to see if your new user registrations are on. If they are but you're not expecting any new user signups, you should disable this in Config, as anyone who knows your onion URL can create accounts on your server.",
|
||||
description: `Checks to see if your new user registrations are on. If they are but you're not expecting any new user signups, you should disable this in Config, as anyone who knows your onion URL can create accounts on your server.`,
|
||||
},
|
||||
'rpc-interface': {
|
||||
name: 'RPC Interface',
|
||||
@@ -577,7 +574,7 @@ export const mockPatchData: DataModel = {
|
||||
'As long as Bitcoin is pruned, LND needs Bitcoin Proxy to fetch block over the P2P network.',
|
||||
requirement: {
|
||||
type: 'opt-in',
|
||||
how: "To use Proxy's user management system, go to LND config and select Bitcoin Proxy under Bitcoin config.",
|
||||
how: `To use Proxy's user management system, go to LND config and select Bitcoin Proxy under Bitcoin config.`,
|
||||
},
|
||||
config: null,
|
||||
},
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { WorkspaceConfig, PackageState } from '@start9labs/shared'
|
||||
import {
|
||||
InterfaceDef,
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
} from './patch-db/data-model'
|
||||
import { WorkspaceConfig } from '@shared'
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
|
||||
const {
|
||||
gitHash,
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import { Injectable, OnDestroy } from "@angular/core";
|
||||
import { ReplaySubject } from "rxjs";
|
||||
|
||||
/**
|
||||
* Observable abstraction over ngOnDestroy to use with takeUntil
|
||||
*/
|
||||
@Injectable()
|
||||
export class DestroyService extends ReplaySubject<void> implements OnDestroy {
|
||||
ngOnDestroy() {
|
||||
this.next();
|
||||
this.complete();
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import * as emver from '@start9labs/emver'
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class Emver {
|
||||
constructor () { }
|
||||
|
||||
compare (lhs: string, rhs: string): number {
|
||||
if (!lhs || !rhs) return null
|
||||
return emver.compare(lhs, rhs)
|
||||
}
|
||||
|
||||
satisfies (version: string, range: string): boolean {
|
||||
return emver.satisfies(version, range)
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'
|
||||
import { BehaviorSubject } from 'rxjs'
|
||||
import { MarketplaceEOS } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { Emver } from 'src/app/services/emver.service'
|
||||
import { Emver } from '@start9labs/shared'
|
||||
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||
|
||||
@Injectable({
|
||||
|
||||
@@ -1,6 +1,31 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { AbstractControl, FormArray, FormBuilder, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators } from '@angular/forms'
|
||||
import { ConfigSpec, isValueSpecListOf, ListValueSpecNumber, ListValueSpecObject, ListValueSpecOf, ListValueSpecString, ListValueSpecUnion, UniqueBy, ValueSpec, ValueSpecEnum, ValueSpecList, ValueSpecNumber, ValueSpecObject, ValueSpecString, ValueSpecUnion } from '../pkg-config/config-types'
|
||||
import {
|
||||
AbstractControl,
|
||||
FormArray,
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
ValidationErrors,
|
||||
ValidatorFn,
|
||||
Validators,
|
||||
} from '@angular/forms'
|
||||
import {
|
||||
ConfigSpec,
|
||||
isValueSpecListOf,
|
||||
ListValueSpecNumber,
|
||||
ListValueSpecObject,
|
||||
ListValueSpecOf,
|
||||
ListValueSpecString,
|
||||
ListValueSpecUnion,
|
||||
UniqueBy,
|
||||
ValueSpec,
|
||||
ValueSpecEnum,
|
||||
ValueSpecList,
|
||||
ValueSpecNumber,
|
||||
ValueSpecObject,
|
||||
ValueSpecString,
|
||||
ValueSpecUnion,
|
||||
} from 'src/app/pkg-config/config-types'
|
||||
import { getDefaultString, Range } from '../pkg-config/config-utilities'
|
||||
const Mustache = require('mustache')
|
||||
|
||||
@@ -8,18 +33,24 @@ const Mustache = require('mustache')
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class FormService {
|
||||
constructor(private readonly formBuilder: FormBuilder) {}
|
||||
|
||||
constructor (
|
||||
private readonly formBuilder: FormBuilder,
|
||||
) { }
|
||||
|
||||
createForm (spec: ConfigSpec, current: { [key: string]: any } = { }): FormGroup {
|
||||
createForm(
|
||||
spec: ConfigSpec,
|
||||
current: { [key: string]: any } = {},
|
||||
): FormGroup {
|
||||
return this.getFormGroup(spec, [], current)
|
||||
}
|
||||
|
||||
getUnionObject (spec: ValueSpecUnion | ListValueSpecUnion, selection: string, current?: { [key: string]: any }): FormGroup {
|
||||
getUnionObject(
|
||||
spec: ValueSpecUnion | ListValueSpecUnion,
|
||||
selection: string,
|
||||
current?: { [key: string]: any },
|
||||
): FormGroup {
|
||||
const { variants, tag } = spec
|
||||
const { name, description, warning } = isFullUnion(spec) ? spec : { ...spec.tag, warning: undefined }
|
||||
const { name, description, warning } = isFullUnion(spec)
|
||||
? spec
|
||||
: { ...spec.tag, warning: undefined }
|
||||
|
||||
const enumSpec: ValueSpecEnum = {
|
||||
type: 'enum',
|
||||
@@ -30,10 +61,14 @@ export class FormService {
|
||||
values: Object.keys(variants),
|
||||
'value-names': tag['variant-names'],
|
||||
}
|
||||
return this.getFormGroup({ [spec.tag.id]: enumSpec, ...spec.variants[selection] }, [], current)
|
||||
return this.getFormGroup(
|
||||
{ [spec.tag.id]: enumSpec, ...spec.variants[selection] },
|
||||
[],
|
||||
current,
|
||||
)
|
||||
}
|
||||
|
||||
getListItem (spec: ValueSpecList, entry: any) {
|
||||
getListItem(spec: ValueSpecList, entry: any) {
|
||||
const listItemValidators = this.getListItemValidators(spec)
|
||||
if (isValueSpecListOf(spec, 'string')) {
|
||||
return this.formBuilder.control(entry, listItemValidators)
|
||||
@@ -48,7 +83,7 @@ export class FormService {
|
||||
}
|
||||
}
|
||||
|
||||
private getListItemValidators (spec: ValueSpecList) {
|
||||
private getListItemValidators(spec: ValueSpecList) {
|
||||
if (isValueSpecListOf(spec, 'string')) {
|
||||
return this.stringValidators(spec.spec)
|
||||
} else if (isValueSpecListOf(spec, 'number')) {
|
||||
@@ -56,16 +91,23 @@ export class FormService {
|
||||
}
|
||||
}
|
||||
|
||||
private getFormGroup (config: ConfigSpec, validators: ValidatorFn[] = [], current: { [key: string]: any } = { }): FormGroup {
|
||||
let group = { }
|
||||
private getFormGroup(
|
||||
config: ConfigSpec,
|
||||
validators: ValidatorFn[] = [],
|
||||
current: { [key: string]: any } = {},
|
||||
): FormGroup {
|
||||
let group = {}
|
||||
Object.entries(config).map(([key, spec]) => {
|
||||
if (spec.type === 'pointer') return
|
||||
group[key] = this.getFormEntry(spec, current ? current[key] : undefined)
|
||||
})
|
||||
return this.formBuilder.group(group, { validators } )
|
||||
return this.formBuilder.group(group, { validators })
|
||||
}
|
||||
|
||||
private getFormEntry (spec: ValueSpec, currentValue?: any): FormGroup | FormArray | FormControl {
|
||||
private getFormEntry(
|
||||
spec: ValueSpec,
|
||||
currentValue?: any,
|
||||
): FormGroup | FormArray | FormControl {
|
||||
let validators: ValidatorFn[]
|
||||
let value: any
|
||||
switch (spec.type) {
|
||||
@@ -89,12 +131,18 @@ export class FormService {
|
||||
return this.getFormGroup(spec.spec, [], currentValue)
|
||||
case 'list':
|
||||
validators = this.listValidators(spec)
|
||||
const mapped = (Array.isArray(currentValue) ? currentValue : spec.default as any[]).map(entry => {
|
||||
const mapped = (
|
||||
Array.isArray(currentValue) ? currentValue : (spec.default as any[])
|
||||
).map(entry => {
|
||||
return this.getListItem(spec, entry)
|
||||
})
|
||||
return this.formBuilder.array(mapped, validators)
|
||||
case 'union':
|
||||
return this.getUnionObject(spec, currentValue?.[spec.tag.id] || spec.default, currentValue)
|
||||
return this.getUnionObject(
|
||||
spec,
|
||||
currentValue?.[spec.tag.id] || spec.default,
|
||||
currentValue,
|
||||
)
|
||||
case 'boolean':
|
||||
case 'enum':
|
||||
value = currentValue === undefined ? spec.default : currentValue
|
||||
@@ -102,7 +150,9 @@ export class FormService {
|
||||
}
|
||||
}
|
||||
|
||||
private stringValidators (spec: ValueSpecString | ListValueSpecString): ValidatorFn[] {
|
||||
private stringValidators(
|
||||
spec: ValueSpecString | ListValueSpecString,
|
||||
): ValidatorFn[] {
|
||||
const validators: ValidatorFn[] = []
|
||||
|
||||
if (!(spec as ValueSpecString).nullable) {
|
||||
@@ -116,7 +166,9 @@ export class FormService {
|
||||
return validators
|
||||
}
|
||||
|
||||
private numberValidators (spec: ValueSpecNumber | ListValueSpecNumber): ValidatorFn[] {
|
||||
private numberValidators(
|
||||
spec: ValueSpecNumber | ListValueSpecNumber,
|
||||
): ValidatorFn[] {
|
||||
const validators: ValidatorFn[] = []
|
||||
|
||||
validators.push(isNumber())
|
||||
@@ -134,7 +186,7 @@ export class FormService {
|
||||
return validators
|
||||
}
|
||||
|
||||
private listValidators (spec: ValueSpecList): ValidatorFn[] {
|
||||
private listValidators(spec: ValueSpecList): ValidatorFn[] {
|
||||
const validators: ValidatorFn[] = []
|
||||
|
||||
validators.push(listInRange(spec.range))
|
||||
@@ -149,11 +201,13 @@ export class FormService {
|
||||
}
|
||||
}
|
||||
|
||||
function isFullUnion (spec: ValueSpecUnion | ListValueSpecUnion): spec is ValueSpecUnion {
|
||||
function isFullUnion(
|
||||
spec: ValueSpecUnion | ListValueSpecUnion,
|
||||
): spec is ValueSpecUnion {
|
||||
return !!(spec as ValueSpecUnion).name
|
||||
}
|
||||
|
||||
export function numberInRange (stringRange: string): ValidatorFn {
|
||||
export function numberInRange(stringRange: string): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
const value = control.value
|
||||
if (!value) return null
|
||||
@@ -166,23 +220,23 @@ export function numberInRange (stringRange: string): ValidatorFn {
|
||||
}
|
||||
}
|
||||
|
||||
export function isNumber (): ValidatorFn {
|
||||
export function isNumber(): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return !control.value || control.value == Number(control.value) ?
|
||||
null :
|
||||
{ notNumber: { value: control.value } }
|
||||
return !control.value || control.value == Number(control.value)
|
||||
? null
|
||||
: { notNumber: { value: control.value } }
|
||||
}
|
||||
}
|
||||
|
||||
export function isInteger (): ValidatorFn {
|
||||
export function isInteger(): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return !control.value || control.value == Math.trunc(control.value) ?
|
||||
null :
|
||||
{ numberNotInteger: { value: control.value } }
|
||||
return !control.value || control.value == Math.trunc(control.value)
|
||||
? null
|
||||
: { numberNotInteger: { value: control.value } }
|
||||
}
|
||||
}
|
||||
|
||||
export function listInRange (stringRange: string): ValidatorFn {
|
||||
export function listInRange(stringRange: string): ValidatorFn {
|
||||
return (control: FormArray): ValidationErrors | null => {
|
||||
try {
|
||||
Range.from(stringRange).checkIncludes(control.value.length)
|
||||
@@ -193,7 +247,7 @@ export function listInRange (stringRange: string): ValidatorFn {
|
||||
}
|
||||
}
|
||||
|
||||
export function listItemIssue (): ValidatorFn {
|
||||
export function listItemIssue(): ValidatorFn {
|
||||
return (parentControl: FormArray): ValidationErrors | null => {
|
||||
const problemChild = parentControl.controls.find(c => c.invalid)
|
||||
if (problemChild) {
|
||||
@@ -204,7 +258,7 @@ export function listItemIssue (): ValidatorFn {
|
||||
}
|
||||
}
|
||||
|
||||
export function listUnique (spec: ValueSpecList): ValidatorFn {
|
||||
export function listUnique(spec: ValueSpecList): ValidatorFn {
|
||||
return (control: FormArray): ValidationErrors | null => {
|
||||
const list = control.value
|
||||
for (let idx = 0; idx < list.length; idx++) {
|
||||
@@ -212,17 +266,33 @@ export function listUnique (spec: ValueSpecList): ValidatorFn {
|
||||
if (listItemEquals(spec, list[idx], list[idx2])) {
|
||||
let display1: string
|
||||
let display2: string
|
||||
let uniqueMessage = isObjectOrUnion(spec.spec) ? uniqueByMessageWrapper(spec.spec['unique-by'], spec.spec, list[idx]) : ''
|
||||
let uniqueMessage = isObjectOrUnion(spec.spec)
|
||||
? uniqueByMessageWrapper(
|
||||
spec.spec['unique-by'],
|
||||
spec.spec,
|
||||
list[idx],
|
||||
)
|
||||
: ''
|
||||
|
||||
if (isObjectOrUnion(spec.spec) && spec.spec['display-as']) {
|
||||
display1 = `"${(Mustache as any).render(spec.spec['display-as'], list[idx])}"`
|
||||
display2 = `"${(Mustache as any).render(spec.spec['display-as'], list[idx2])}"`
|
||||
display1 = `"${(Mustache as any).render(
|
||||
spec.spec['display-as'],
|
||||
list[idx],
|
||||
)}"`
|
||||
display2 = `"${(Mustache as any).render(
|
||||
spec.spec['display-as'],
|
||||
list[idx2],
|
||||
)}"`
|
||||
} else {
|
||||
display1 = `Entry ${idx + 1}`
|
||||
display2 = `Entry ${idx2 + 1}`
|
||||
}
|
||||
|
||||
return { listNotUnique: { value: `${display1} and ${display2} are not unique.${uniqueMessage}` } }
|
||||
return {
|
||||
listNotUnique: {
|
||||
value: `${display1} and ${display2} are not unique.${uniqueMessage}`,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -230,22 +300,32 @@ export function listUnique (spec: ValueSpecList): ValidatorFn {
|
||||
}
|
||||
}
|
||||
|
||||
function listItemEquals (spec: ValueSpecList, val1: any, val2: any): boolean {
|
||||
function listItemEquals(spec: ValueSpecList, val1: any, val2: any): boolean {
|
||||
switch (spec.subtype) {
|
||||
case 'string':
|
||||
case 'number':
|
||||
case 'enum':
|
||||
return val1 == val2
|
||||
case 'object':
|
||||
return listObjEquals(spec.spec['unique-by'], (spec.spec as ListValueSpecObject), val1, val2)
|
||||
return listObjEquals(
|
||||
spec.spec['unique-by'],
|
||||
spec.spec as ListValueSpecObject,
|
||||
val1,
|
||||
val2,
|
||||
)
|
||||
case 'union':
|
||||
return unionEquals(spec.spec['unique-by'], spec.spec as ListValueSpecUnion, val1, val2)
|
||||
return unionEquals(
|
||||
spec.spec['unique-by'],
|
||||
spec.spec as ListValueSpecUnion,
|
||||
val1,
|
||||
val2,
|
||||
)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function itemEquals (spec: ValueSpec, val1: any, val2: any): boolean {
|
||||
function itemEquals(spec: ValueSpec, val1: any, val2: any): boolean {
|
||||
switch (spec.type) {
|
||||
case 'string':
|
||||
case 'number':
|
||||
@@ -253,9 +333,9 @@ function itemEquals (spec: ValueSpec, val1: any, val2: any): boolean {
|
||||
case 'enum':
|
||||
return val1 == val2
|
||||
case 'object':
|
||||
return objEquals(spec['unique-by'], (spec as ValueSpecObject), val1, val2)
|
||||
return objEquals(spec['unique-by'], spec as ValueSpecObject, val1, val2)
|
||||
case 'union':
|
||||
return unionEquals(spec['unique-by'], (spec as ValueSpecUnion), val1, val2)
|
||||
return unionEquals(spec['unique-by'], spec as ValueSpecUnion, val1, val2)
|
||||
case 'list':
|
||||
if (val1.length !== val2.length) {
|
||||
return false
|
||||
@@ -271,7 +351,12 @@ function itemEquals (spec: ValueSpec, val1: any, val2: any): boolean {
|
||||
}
|
||||
}
|
||||
|
||||
function listObjEquals (uniqueBy: UniqueBy, spec: ListValueSpecObject, val1: any, val2: any): boolean {
|
||||
function listObjEquals(
|
||||
uniqueBy: UniqueBy,
|
||||
spec: ListValueSpecObject,
|
||||
val1: any,
|
||||
val2: any,
|
||||
): boolean {
|
||||
if (uniqueBy === null) {
|
||||
return false
|
||||
} else if (typeof uniqueBy === 'string') {
|
||||
@@ -293,7 +378,12 @@ function listObjEquals (uniqueBy: UniqueBy, spec: ListValueSpecObject, val1: any
|
||||
}
|
||||
}
|
||||
|
||||
function objEquals (uniqueBy: UniqueBy, spec: ValueSpecObject, val1: any, val2: any): boolean {
|
||||
function objEquals(
|
||||
uniqueBy: UniqueBy,
|
||||
spec: ValueSpecObject,
|
||||
val1: any,
|
||||
val2: any,
|
||||
): boolean {
|
||||
if (uniqueBy === null) {
|
||||
return false
|
||||
} else if (typeof uniqueBy === 'string') {
|
||||
@@ -315,7 +405,12 @@ function objEquals (uniqueBy: UniqueBy, spec: ValueSpecObject, val1: any, val2:
|
||||
}
|
||||
}
|
||||
|
||||
function unionEquals (uniqueBy: UniqueBy, spec: ValueSpecUnion | ListValueSpecUnion, val1: any, val2: any): boolean {
|
||||
function unionEquals(
|
||||
uniqueBy: UniqueBy,
|
||||
spec: ValueSpecUnion | ListValueSpecUnion,
|
||||
val1: any,
|
||||
val2: any,
|
||||
): boolean {
|
||||
const tagId = spec.tag.id
|
||||
const variant = spec.variants[val1[tagId]]
|
||||
if (uniqueBy === null) {
|
||||
@@ -343,7 +438,11 @@ function unionEquals (uniqueBy: UniqueBy, spec: ValueSpecUnion | ListValueSpecUn
|
||||
}
|
||||
}
|
||||
|
||||
function uniqueByMessageWrapper (uniqueBy: UniqueBy, spec: ListValueSpecObject | ListValueSpecUnion, obj: object) {
|
||||
function uniqueByMessageWrapper(
|
||||
uniqueBy: UniqueBy,
|
||||
spec: ListValueSpecObject | ListValueSpecUnion,
|
||||
obj: object,
|
||||
) {
|
||||
let configSpec: ConfigSpec
|
||||
if (isUnion(spec)) {
|
||||
const variantKey = obj[spec.tag.id]
|
||||
@@ -358,7 +457,11 @@ function uniqueByMessageWrapper (uniqueBy: UniqueBy, spec: ListValueSpecObject |
|
||||
}
|
||||
}
|
||||
|
||||
function uniqueByMessage (uniqueBy: UniqueBy, configSpec: ConfigSpec, outermost = true): string {
|
||||
function uniqueByMessage(
|
||||
uniqueBy: UniqueBy,
|
||||
configSpec: ConfigSpec,
|
||||
outermost = true,
|
||||
): string {
|
||||
let joinFunc
|
||||
const subSpecs = []
|
||||
if (uniqueBy === null) {
|
||||
@@ -377,20 +480,27 @@ function uniqueByMessage (uniqueBy: UniqueBy, configSpec: ConfigSpec, outermost
|
||||
}
|
||||
}
|
||||
const ret = subSpecs.filter(ss => ss).join(joinFunc)
|
||||
return outermost || subSpecs.filter(ss => ss).length === 1 ? ret : '(' + ret + ')'
|
||||
return outermost || subSpecs.filter(ss => ss).length === 1
|
||||
? ret
|
||||
: '(' + ret + ')'
|
||||
}
|
||||
|
||||
function isObjectOrUnion (spec: ListValueSpecOf<any>): spec is ListValueSpecObject | ListValueSpecUnion {
|
||||
function isObjectOrUnion(
|
||||
spec: ListValueSpecOf<any>,
|
||||
): spec is ListValueSpecObject | ListValueSpecUnion {
|
||||
// only lists of objects and unions have unique-by
|
||||
return spec['unique-by'] !== undefined
|
||||
}
|
||||
|
||||
function isUnion (spec: any): spec is ListValueSpecUnion {
|
||||
function isUnion(spec: any): spec is ListValueSpecUnion {
|
||||
// only unions have tag
|
||||
return !!spec.tag
|
||||
}
|
||||
|
||||
export function convertValuesRecursive (configSpec: ConfigSpec, group: FormGroup) {
|
||||
export function convertValuesRecursive(
|
||||
configSpec: ConfigSpec,
|
||||
group: FormGroup,
|
||||
) {
|
||||
Object.entries(configSpec).forEach(([key, valueSpec]) => {
|
||||
if (valueSpec.type === 'number') {
|
||||
const control = group.get(key)
|
||||
@@ -422,7 +532,8 @@ export function convertValuesRecursive (configSpec: ConfigSpec, group: FormGroup
|
||||
} else if (valueSpec.subtype === 'union') {
|
||||
formArr.controls.forEach((formGroup: FormGroup) => {
|
||||
const unionSpec = valueSpec.spec as ListValueSpecUnion
|
||||
const spec = unionSpec.variants[formGroup.controls[unionSpec.tag.id].value]
|
||||
const spec =
|
||||
unionSpec.variants[formGroup.controls[unionSpec.tag.id].value]
|
||||
convertValuesRecursive(spec, formGroup)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { ModalController } from '@ionic/angular'
|
||||
import { DependentInfo } from 'src/app/util/misc.util'
|
||||
import { DependentInfo } from '@start9labs/shared'
|
||||
import { AppConfigPage } from 'src/app/modals/app-config/app-config.page'
|
||||
|
||||
@Injectable({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import { InstallProgress, PackageState } from '@start9labs/shared'
|
||||
|
||||
export interface DataModel {
|
||||
'server-info': ServerInfo
|
||||
@@ -64,16 +65,6 @@ export interface PackageDataEntry {
|
||||
'install-progress'?: InstallProgress // exists when: installing, updating
|
||||
}
|
||||
|
||||
export interface InstallProgress {
|
||||
size: number | null
|
||||
downloaded: number
|
||||
'download-complete': boolean
|
||||
validated: number
|
||||
'validation-complete': boolean
|
||||
unpacked: number
|
||||
'unpack-complete': boolean
|
||||
}
|
||||
|
||||
export interface InstalledPackageDataEntry {
|
||||
status: Status
|
||||
manifest: Manifest
|
||||
@@ -99,14 +90,6 @@ export interface CurrentDependencyInfo {
|
||||
'health-checks': string[] // array of health check IDs
|
||||
}
|
||||
|
||||
export enum PackageState {
|
||||
Installing = 'installing',
|
||||
Installed = 'installed',
|
||||
Updating = 'updating',
|
||||
Removing = 'removing',
|
||||
Restoring = 'restoring',
|
||||
}
|
||||
|
||||
export interface Manifest {
|
||||
id: string
|
||||
title: string
|
||||
@@ -377,17 +360,17 @@ export interface DependencyInfo {
|
||||
export interface DependencyEntry {
|
||||
version: string
|
||||
requirement:
|
||||
| {
|
||||
type: 'opt-in'
|
||||
how: string
|
||||
}
|
||||
| {
|
||||
type: 'opt-out'
|
||||
how: string
|
||||
}
|
||||
| {
|
||||
type: 'required'
|
||||
}
|
||||
| {
|
||||
type: 'opt-in'
|
||||
how: string
|
||||
}
|
||||
| {
|
||||
type: 'opt-out'
|
||||
how: string
|
||||
}
|
||||
| {
|
||||
type: 'required'
|
||||
}
|
||||
description: string | null
|
||||
config: {
|
||||
check: ActionImpl
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Bootstrapper, DBCache } from 'patch-db-client'
|
||||
import { DataModel } from './data-model'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { Storage } from '@ionic/storage-angular'
|
||||
|
||||
@@ -9,16 +9,16 @@ import { Storage } from '@ionic/storage-angular'
|
||||
export class LocalStorageBootstrap implements Bootstrapper<DataModel> {
|
||||
static CONTENT_KEY = 'patch-db-cache'
|
||||
|
||||
constructor (
|
||||
private readonly storage: Storage,
|
||||
) { }
|
||||
constructor(private readonly storage: Storage) {}
|
||||
|
||||
async init (): Promise<DBCache<DataModel>> {
|
||||
const cache: DBCache<DataModel> = await this.storage.get(LocalStorageBootstrap.CONTENT_KEY)
|
||||
return cache || { sequence: 0, data: { } as DataModel }
|
||||
async init(): Promise<DBCache<DataModel>> {
|
||||
const cache: DBCache<DataModel> = await this.storage.get(
|
||||
LocalStorageBootstrap.CONTENT_KEY,
|
||||
)
|
||||
return cache || { sequence: 0, data: {} as DataModel }
|
||||
}
|
||||
|
||||
async update (cache: DBCache<DataModel>): Promise<void> {
|
||||
async update(cache: DBCache<DataModel>): Promise<void> {
|
||||
await this.storage.set(LocalStorageBootstrap.CONTENT_KEY, cache)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
import { MockSource, PollSource, WebsocketSource } from 'patch-db-client'
|
||||
import { ConfigService } from 'src/app/services/config.service'
|
||||
import { DataModel } from './data-model'
|
||||
import { LocalStorageBootstrap } from './local-storage-bootstrap'
|
||||
import { PatchDbService } from './patch-db.service'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { AuthService } from '../auth.service'
|
||||
import { MockApiService } from '../api/embassy-mock-api.service'
|
||||
import { filter } from 'rxjs/operators'
|
||||
import { exists } from 'src/app/util/misc.util'
|
||||
import { exists } from '@start9labs/shared'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { Storage } from '@ionic/storage-angular'
|
||||
|
||||
export function PatchDbServiceFactory (
|
||||
export function PatchDbServiceFactory(
|
||||
config: ConfigService,
|
||||
embassyApi: ApiService,
|
||||
bootstrapper: LocalStorageBootstrap,
|
||||
auth: AuthService,
|
||||
storage: Storage,
|
||||
): PatchDbService {
|
||||
|
||||
const { useMocks, patchDb: { poll } } = config
|
||||
const {
|
||||
useMocks,
|
||||
patchDb: { poll },
|
||||
} = config
|
||||
|
||||
if (useMocks) {
|
||||
const source = new MockSource<DataModel>(
|
||||
|
||||
@@ -10,10 +10,10 @@ import {
|
||||
tap,
|
||||
withLatestFrom,
|
||||
} from 'rxjs/operators'
|
||||
import { isEmptyObject, pauseFor } from 'src/app/util/misc.util'
|
||||
import { isEmptyObject, pauseFor } from '@start9labs/shared'
|
||||
import { DataModel } from './data-model'
|
||||
import { ApiService } from '../api/embassy-api.service'
|
||||
import { AuthService } from '../auth.service'
|
||||
import { DataModel } from './data-model'
|
||||
|
||||
export const PATCH_HTTP = new InjectionToken<Source<DataModel>>('')
|
||||
export const PATCH_SOURCE = new InjectionToken<Source<DataModel>>('')
|
||||
@@ -44,15 +44,18 @@ export class PatchDbService {
|
||||
data: DataModel
|
||||
errors = 0
|
||||
|
||||
getData () {
|
||||
getData() {
|
||||
return this.patchDb.store.cache.data
|
||||
}
|
||||
|
||||
get loaded (): boolean {
|
||||
return this.patchDb?.store?.cache?.data && !isEmptyObject(this.patchDb.store.cache.data)
|
||||
get loaded(): boolean {
|
||||
return (
|
||||
this.patchDb?.store?.cache?.data &&
|
||||
!isEmptyObject(this.patchDb.store.cache.data)
|
||||
)
|
||||
}
|
||||
|
||||
constructor (
|
||||
constructor(
|
||||
@Inject(PATCH_SOURCE) private readonly wsSource: Source<DataModel>,
|
||||
@Inject(PATCH_SOURCE) private readonly pollSource: Source<DataModel>,
|
||||
@Inject(PATCH_HTTP) private readonly http: ApiService,
|
||||
@@ -60,9 +63,9 @@ export class PatchDbService {
|
||||
private readonly bootstrapper: Bootstrapper<DataModel>,
|
||||
@Inject(AUTH) private readonly auth: AuthService,
|
||||
@Inject(STORAGE) private readonly storage: Storage,
|
||||
) { }
|
||||
) {}
|
||||
|
||||
async init (): Promise<void> {
|
||||
async init(): Promise<void> {
|
||||
const cache = await this.bootstrapper.init()
|
||||
this.sources$.next([this.wsSource, this.http])
|
||||
|
||||
@@ -72,7 +75,7 @@ export class PatchDbService {
|
||||
this.data = this.patchDb.store.cache.data
|
||||
}
|
||||
|
||||
async start (): Promise<void> {
|
||||
async start(): Promise<void> {
|
||||
await this.init()
|
||||
|
||||
this.subs.push(
|
||||
@@ -156,26 +159,27 @@ export class PatchDbService {
|
||||
)
|
||||
}
|
||||
|
||||
stop (): void {
|
||||
stop(): void {
|
||||
if (this.patchDb) {
|
||||
console.log('patchDB: STOPPING')
|
||||
this.patchConnection$.next(PatchConnection.Initializing)
|
||||
this.patchDb.store.reset()
|
||||
}
|
||||
this.subs.forEach((x) => x.unsubscribe())
|
||||
this.subs.forEach(x => x.unsubscribe())
|
||||
this.subs = []
|
||||
}
|
||||
|
||||
watchPatchConnection$ (): Observable<PatchConnection> {
|
||||
watchPatchConnection$(): Observable<PatchConnection> {
|
||||
return this.patchConnection$.asObservable()
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
watch$: Store<DataModel>['watch$'] = (...args: (string | number)[]): Observable<DataModel> => {
|
||||
const argsString = '/' + args.join('/')
|
||||
console.log('patchDB: WATCHING ', argsString)
|
||||
return this.patchDb.store.watch$(...(args as [])).pipe(
|
||||
tap((data) => console.log('patchDB: NEW VALUE', argsString, data)),
|
||||
catchError((e) => {
|
||||
tap(data => console.log('patchDB: NEW VALUE', argsString, data)),
|
||||
catchError(e => {
|
||||
console.error('patchDB: WATCH ERROR', e)
|
||||
return of(e.message)
|
||||
}),
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { isEmptyObject } from '../util/misc.util'
|
||||
import { isEmptyObject, PackageState } from '@start9labs/shared'
|
||||
import {
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
Status,
|
||||
} from './patch-db/data-model'
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
|
||||
export interface PackageStatus {
|
||||
primary: PrimaryStatus
|
||||
@@ -95,25 +94,61 @@ export enum HealthStatus {
|
||||
Healthy = 'healthy',
|
||||
}
|
||||
|
||||
export const PrimaryRendering: { [key: string]: StatusRendering } = {
|
||||
[PrimaryStatus.Installing]: { display: 'Installing', color: 'primary', showDots: true },
|
||||
[PrimaryStatus.Updating]: { display: 'Updating', color: 'primary', showDots: true },
|
||||
[PrimaryStatus.Removing]: { display: 'Removing', color: 'danger', showDots: true },
|
||||
[PrimaryStatus.Restoring]: { display: 'Restoring', color: 'primary', showDots: true },
|
||||
[PrimaryStatus.Stopping]: { display: 'Stopping', color: 'dark-shade', showDots: true },
|
||||
[PrimaryStatus.Stopped]: { display: 'Stopped', color: 'dark-shade', showDots: false },
|
||||
[PrimaryStatus.BackingUp]: { display: 'Backing Up', color: 'primary', showDots: true },
|
||||
[PrimaryStatus.Starting]: { display: 'Starting', color: 'primary', showDots: true },
|
||||
[PrimaryStatus.Running]: { display: 'Running', color: 'success', showDots: false },
|
||||
export const PrimaryRendering: Record<string, StatusRendering> = {
|
||||
[PrimaryStatus.Installing]: {
|
||||
display: 'Installing',
|
||||
color: 'primary',
|
||||
showDots: true,
|
||||
},
|
||||
[PrimaryStatus.Updating]: {
|
||||
display: 'Updating',
|
||||
color: 'primary',
|
||||
showDots: true,
|
||||
},
|
||||
[PrimaryStatus.Removing]: {
|
||||
display: 'Removing',
|
||||
color: 'danger',
|
||||
showDots: true,
|
||||
},
|
||||
[PrimaryStatus.Restoring]: {
|
||||
display: 'Restoring',
|
||||
color: 'primary',
|
||||
showDots: true,
|
||||
},
|
||||
[PrimaryStatus.Stopping]: {
|
||||
display: 'Stopping',
|
||||
color: 'dark-shade',
|
||||
showDots: true,
|
||||
},
|
||||
[PrimaryStatus.Stopped]: {
|
||||
display: 'Stopped',
|
||||
color: 'dark-shade',
|
||||
showDots: false,
|
||||
},
|
||||
[PrimaryStatus.BackingUp]: {
|
||||
display: 'Backing Up',
|
||||
color: 'primary',
|
||||
showDots: true,
|
||||
},
|
||||
[PrimaryStatus.Starting]: {
|
||||
display: 'Starting',
|
||||
color: 'primary',
|
||||
showDots: true,
|
||||
},
|
||||
[PrimaryStatus.Running]: {
|
||||
display: 'Running',
|
||||
color: 'success',
|
||||
showDots: false,
|
||||
},
|
||||
[PrimaryStatus.NeedsConfig]: { display: 'Needs Config', color: 'warning' },
|
||||
}
|
||||
|
||||
export const DependencyRendering: { [key: string]: StatusRendering } = {
|
||||
export const DependencyRendering: Record<string, StatusRendering> = {
|
||||
[DependencyStatus.Warning]: { display: 'Issue', color: 'warning' },
|
||||
[DependencyStatus.Satisfied]: { display: 'Satisfied', color: 'success' },
|
||||
}
|
||||
|
||||
export const HealthRendering: { [key: string]: StatusRendering } = {
|
||||
export const HealthRendering: Record<string, StatusRendering> = {
|
||||
[HealthStatus.Failure]: { display: 'Failure', color: 'danger' },
|
||||
[HealthStatus.Starting]: { display: 'Starting', color: 'primary' },
|
||||
[HealthStatus.Loading]: { display: 'Loading', color: 'primary' },
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { AlertInput, AlertButton } from '@ionic/core'
|
||||
import { ApiService } from './api/embassy-api.service'
|
||||
import { ConfigSpec } from '../pkg-config/config-types'
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import { AlertController, LoadingController } from '@ionic/angular'
|
||||
import { ErrorToastService } from './error-toast.service'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Inject, Injectable } from '@angular/core'
|
||||
import { DOCUMENT } from '@angular/common'
|
||||
import { PackageDataEntry } from './patch-db/data-model'
|
||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||
import { ConfigService } from './config.service'
|
||||
|
||||
@Injectable({
|
||||
|
||||
Reference in New Issue
Block a user