update sdk imports

This commit is contained in:
Matt Hill
2024-03-24 13:27:13 -06:00
parent a730a3719b
commit af0cda5dbf
44 changed files with 292 additions and 353 deletions

View File

@@ -1,23 +0,0 @@
{
"projects": {
"ui": {
"name": "ui",
"integrations": {},
"type": "angular",
"root": "projects/ui"
},
"install-wizard": {
"name": "install-wizard",
"integrations": {},
"type": "angular",
"root": "projects/install-wizard"
},
"setup-wizard": {
"name": "setup-wizard",
"integrations": {},
"type": "angular",
"root": "projects/setup-wizard"
}
},
"defaultProject": "ui"
}

View File

@@ -1,9 +1,9 @@
{ {
"name": null, "name": null,
"ack-welcome": "0.3.4.4", "ackWelcome": "0.3.4.4",
"marketplace": { "marketplace": {
"selected-url": "https://registry.start9.com/", "selectedUrl": "https://registry.start9.com/",
"known-hosts": { "knownHosts": {
"https://registry.start9.com/": {}, "https://registry.start9.com/": {},
"https://community-registry.start9.com/": {} "https://community-registry.start9.com/": {}
} }
@@ -11,10 +11,10 @@
"dev": {}, "dev": {},
"gaming": { "gaming": {
"snake": { "snake": {
"high-score": 0 "highScore": 0
} }
}, },
"ack-instructions": {}, "ackInstructions": {},
"theme": "Dark", "theme": "Dark",
"widgets": [] "widgets": []
} }

View File

@@ -8,7 +8,8 @@ import {
} from '@angular/core' } from '@angular/core'
import { FormGroup, ReactiveFormsModule } from '@angular/forms' import { FormGroup, ReactiveFormsModule } from '@angular/forms'
import { RouterModule } from '@angular/router' import { RouterModule } from '@angular/router'
import { InputSpec } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { import {
tuiMarkControlAsTouchedAndValidate, tuiMarkControlAsTouchedAndValidate,
TuiValueChangesModule, TuiValueChangesModule,
@@ -29,7 +30,7 @@ export interface ActionButton<T> {
} }
export interface FormContext<T> { export interface FormContext<T> {
spec: InputSpec spec: CT.InputSpec
buttons: ActionButton<T>[] buttons: ActionButton<T>[]
value?: T value?: T
patch?: Operation[] patch?: Operation[]

View File

@@ -1,7 +1,4 @@
import { T } from '@start9labs/start-sdk' import { CB, CT, T } from '@start9labs/start-sdk'
import { Config } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/config'
import { Value } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/value'
import { InputSpec } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes'
import { TuiDialogOptions } from '@taiga-ui/core' import { TuiDialogOptions } from '@taiga-ui/core'
import { TuiPromptData } from '@taiga-ui/kit' import { TuiPromptData } from '@taiga-ui/kit'
import { NetworkInfo } from 'src/app/services/patch-db/data-model' import { NetworkInfo } from 'src/app/services/patch-db/data-model'
@@ -20,7 +17,7 @@ export const REMOVE: Partial<TuiDialogOptions<TuiPromptData>> = {
export function getClearnetSpec({ export function getClearnetSpec({
domains, domains,
start9ToSubdomain, start9ToSubdomain,
}: NetworkInfo): Promise<InputSpec> { }: NetworkInfo): Promise<CT.InputSpec> {
const start9ToDomain = `${start9ToSubdomain?.value}.start9.to` const start9ToDomain = `${start9ToSubdomain?.value}.start9.to`
const base = start9ToSubdomain ? { [start9ToDomain]: start9ToDomain } : {} const base = start9ToSubdomain ? { [start9ToDomain]: start9ToDomain } : {}
@@ -32,13 +29,13 @@ export function getClearnetSpec({
}, base) }, base)
return configBuilderToSpec( return configBuilderToSpec(
Config.of({ CB.Config.of({
domain: Value.select({ domain: CB.Value.select({
name: 'Domain', name: 'Domain',
required: { default: null }, required: { default: null },
values, values,
}), }),
subdomain: Value.text({ subdomain: CB.Value.text({
name: 'Subdomain', name: 'Subdomain',
required: false, required: false,
}), }),

View File

@@ -6,7 +6,7 @@ import {
isEmptyObject, isEmptyObject,
LoadingService, LoadingService,
} from '@start9labs/shared' } from '@start9labs/shared'
import { InputSpec } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { TuiButtonModule } from '@taiga-ui/experimental' import { TuiButtonModule } from '@taiga-ui/experimental'
import { import {
TuiDialogContext, TuiDialogContext,
@@ -131,7 +131,7 @@ export class ServiceConfigModal {
: 'Loading Config' : 'Loading Config'
pkg?: PackageDataEntry pkg?: PackageDataEntry
spec: InputSpec = {} spec: CT.InputSpec = {}
patch: Operation[] = [] patch: Operation[] = []
buttons: ActionButton<any>[] = [ buttons: ActionButton<any>[] = [
{ {

View File

@@ -1,6 +1,6 @@
import { Pipe, PipeTransform } from '@angular/core' import { Pipe, PipeTransform } from '@angular/core'
import { WithId } from '@start9labs/shared' import { WithId } from '@start9labs/shared'
import { ActionMetadata } from '@start9labs/start-sdk/cjs/sdk/lib/types' import { T } from '@start9labs/start-sdk'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model' import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
@Pipe({ @Pipe({
@@ -10,12 +10,12 @@ import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
export class GroupActionsPipe implements PipeTransform { export class GroupActionsPipe implements PipeTransform {
transform( transform(
actions: PackageDataEntry['actions'], actions: PackageDataEntry['actions'],
): Array<Array<WithId<ActionMetadata>>> | null { ): Array<Array<WithId<T.ActionMetadata>>> | null {
if (!actions) return null if (!actions) return null
const noGroup = 'noGroup' const noGroup = 'noGroup'
const grouped = Object.entries(actions).reduce< const grouped = Object.entries(actions).reduce<
Record<string, WithId<ActionMetadata>[]> Record<string, WithId<T.ActionMetadata>[]>
>((groups, [id, action]) => { >((groups, [id, action]) => {
const actionWithId = { id, ...action } const actionWithId = { id, ...action }
const groupKey = action.group || noGroup const groupKey = action.group || noGroup

View File

@@ -1,8 +1,8 @@
import { Pipe, PipeTransform } from '@angular/core' import { Pipe, PipeTransform } from '@angular/core'
import { ServiceInterfaceWithHostInfo } from '@start9labs/start-sdk/cjs/sdk/lib/types' import { T } from '@start9labs/start-sdk'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model' import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
export interface ExtendedInterfaceInfo extends ServiceInterfaceWithHostInfo { export interface ExtendedInterfaceInfo extends T.ServiceInterfaceWithHostInfo {
id: string id: string
icon: string icon: string
color: string color: string

View File

@@ -26,7 +26,7 @@ import { ServiceActionComponent } from '../components/action.component'
import { ServiceActionSuccessComponent } from '../components/action-success.component' import { ServiceActionSuccessComponent } from '../components/action-success.component'
import { GroupActionsPipe } from '../pipes/group-actions.pipe' import { GroupActionsPipe } from '../pipes/group-actions.pipe'
import { ToManifestPipe } from 'src/app/apps/portal/pipes/to-manifest' import { ToManifestPipe } from 'src/app/apps/portal/pipes/to-manifest'
import { ActionMetadata } from '@start9labs/start-sdk/cjs/sdk/lib/types' import { T } from '@start9labs/start-sdk'
import { getAllPackages, getManifest } from 'src/app/util/get-package-data' import { getAllPackages, getManifest } from 'src/app/util/get-package-data'
@Component({ @Component({
@@ -61,7 +61,12 @@ import { getAllPackages, getManifest } from 'src/app/util/get-package-data'
`, `,
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true, standalone: true,
imports: [CommonModule, ServiceActionComponent, GroupActionsPipe, ToManifestPipe], imports: [
CommonModule,
ServiceActionComponent,
GroupActionsPipe,
ToManifestPipe,
],
}) })
export class ServiceActionsRoute { export class ServiceActionsRoute {
private readonly id = getPkgId(inject(ActivatedRoute)) private readonly id = getPkgId(inject(ActivatedRoute))
@@ -87,7 +92,7 @@ export class ServiceActionsRoute {
private readonly formDialog: FormDialogService, private readonly formDialog: FormDialogService,
) {} ) {}
async handleAction(action: WithId<ActionMetadata>) { async handleAction(action: WithId<T.ActionMetadata>) {
if (action.disabled) { if (action.disabled) {
this.dialogs this.dialogs
.open(action.disabled, { .open(action.disabled, {

View File

@@ -1,10 +1,7 @@
import { CommonModule } from '@angular/common' import { CommonModule } from '@angular/common'
import { Component, inject, OnInit } from '@angular/core' import { Component, inject, OnInit } from '@angular/core'
import { ErrorService, LoadingService } from '@start9labs/shared' import { ErrorService, LoadingService } from '@start9labs/shared'
import { import { CT } from '@start9labs/start-sdk'
unionSelectKey,
unionValueKey,
} from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes'
import { TuiNotificationModule } from '@taiga-ui/core' import { TuiNotificationModule } from '@taiga-ui/core'
import { TuiButtonModule, TuiFadeModule } from '@taiga-ui/experimental' import { TuiButtonModule, TuiFadeModule } from '@taiga-ui/experimental'
import { PolymorpheusComponent } from '@tinkoff/ng-polymorpheus' import { PolymorpheusComponent } from '@tinkoff/ng-polymorpheus'
@@ -182,8 +179,8 @@ export class BackupsTargetsModal implements OnInit {
text: 'Save', text: 'Save',
handler: ({ type }: BackupConfig) => handler: ({ type }: BackupConfig) =>
this.add( this.add(
type[unionSelectKey] === 'cifs' ? 'cifs' : 'cloud', type[CT.unionSelectKey] === 'cifs' ? 'cifs' : 'cloud',
type[unionValueKey], type[CT.unionValueKey],
), ),
}, },
], ],

View File

@@ -1,19 +1,16 @@
import { import { CT } from '@start9labs/start-sdk'
unionSelectKey,
unionValueKey,
} from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes'
import { RR } from 'src/app/services/api/api.types' import { RR } from 'src/app/services/api/api.types'
export type BackupConfig = export type BackupConfig =
| { | {
type: { type: {
[unionSelectKey]: 'dropbox' | 'google-drive' [CT.unionSelectKey]: 'dropbox' | 'google-drive'
[unionValueKey]: RR.AddCloudBackupTargetReq [CT.unionValueKey]: RR.AddCloudBackupTargetReq
} }
} }
| { | {
type: { type: {
[unionSelectKey]: 'cifs' [CT.unionSelectKey]: 'cifs'
[unionValueKey]: RR.AddCifsBackupTargetReq [CT.unionValueKey]: RR.AddCifsBackupTargetReq
} }
} }

View File

@@ -1,21 +1,19 @@
import { Config } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/config' import { CB } from '@start9labs/start-sdk'
import { Value } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/value'
import { Variants } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/variants'
export const dropboxSpec = Config.of({ export const dropboxSpec = CB.Config.of({
name: Value.text({ name: CB.Value.text({
name: 'Name', name: 'Name',
description: 'A friendly name for this Dropbox target', description: 'A friendly name for this Dropbox target',
placeholder: 'My Dropbox', placeholder: 'My Dropbox',
required: { default: null }, required: { default: null },
}), }),
token: Value.text({ token: CB.Value.text({
name: 'Access Token', name: 'Access Token',
description: 'The secret access token for your custom Dropbox app', description: 'The secret access token for your custom Dropbox app',
required: { default: null }, required: { default: null },
masked: true, masked: true,
}), }),
path: Value.text({ path: CB.Value.text({
name: 'Path', name: 'Path',
description: 'The fully qualified path to the backup directory', description: 'The fully qualified path to the backup directory',
placeholder: 'e.g. /Desktop/my-folder', placeholder: 'e.g. /Desktop/my-folder',
@@ -23,20 +21,20 @@ export const dropboxSpec = Config.of({
}), }),
}) })
export const googleDriveSpec = Config.of({ export const googleDriveSpec = CB.Config.of({
name: Value.text({ name: CB.Value.text({
name: 'Name', name: 'Name',
description: 'A friendly name for this Google Drive target', description: 'A friendly name for this Google Drive target',
placeholder: 'My Google Drive', placeholder: 'My Google Drive',
required: { default: null }, required: { default: null },
}), }),
path: Value.text({ path: CB.Value.text({
name: 'Path', name: 'Path',
description: 'The fully qualified path to the backup directory', description: 'The fully qualified path to the backup directory',
placeholder: 'e.g. /Desktop/my-folder', placeholder: 'e.g. /Desktop/my-folder',
required: { default: null }, required: { default: null },
}), }),
key: Value.file({ key: CB.Value.file({
name: 'Private Key File', name: 'Private Key File',
description: description:
'Your Google Drive service account private key file (.json file)', 'Your Google Drive service account private key file (.json file)',
@@ -45,14 +43,14 @@ export const googleDriveSpec = Config.of({
}), }),
}) })
export const cifsSpec = Config.of({ export const cifsSpec = CB.Config.of({
name: Value.text({ name: CB.Value.text({
name: 'Name', name: 'Name',
description: 'A friendly name for this Network Folder', description: 'A friendly name for this Network Folder',
placeholder: 'My Network Folder', placeholder: 'My Network Folder',
required: { default: null }, required: { default: null },
}), }),
hostname: Value.text({ hostname: CB.Value.text({
name: 'Hostname', name: 'Hostname',
description: description:
'The hostname of your target device on the Local Area Network.', 'The hostname of your target device on the Local Area Network.',
@@ -61,19 +59,19 @@ export const cifsSpec = Config.of({
required: { default: null }, required: { default: null },
patterns: [], patterns: [],
}), }),
path: Value.text({ path: CB.Value.text({
name: 'Path', name: 'Path',
description: `On Windows, this is the fully qualified path to the shared folder, (e.g. /Desktop/my-folder).\n\n On Linux and Mac, this is the literal name of the shared folder (e.g. my-shared-folder).`, description: `On Windows, this is the fully qualified path to the shared folder, (e.g. /Desktop/my-folder).\n\n On Linux and Mac, this is the literal name of the shared folder (e.g. my-shared-folder).`,
placeholder: 'e.g. my-shared-folder or /Desktop/my-folder', placeholder: 'e.g. my-shared-folder or /Desktop/my-folder',
required: { default: null }, required: { default: null },
}), }),
username: Value.text({ username: CB.Value.text({
name: 'Username', name: 'Username',
description: `On Linux, this is the samba username you created when sharing the folder.\n\n On Mac and Windows, this is the username of the user who is sharing the folder.`, description: `On Linux, this is the samba username you created when sharing the folder.\n\n On Mac and Windows, this is the username of the user who is sharing the folder.`,
required: { default: null }, required: { default: null },
placeholder: 'My Network Folder', placeholder: 'My Network Folder',
}), }),
password: Value.text({ password: CB.Value.text({
name: 'Password', name: 'Password',
description: `On Linux, this is the samba password you created when sharing the folder.\n\n On Mac and Windows, this is the password of the user who is sharing the folder.`, description: `On Linux, this is the samba password you created when sharing the folder.\n\n On Mac and Windows, this is the password of the user who is sharing the folder.`,
required: false, required: false,
@@ -82,13 +80,13 @@ export const cifsSpec = Config.of({
}), }),
}) })
export const remoteBackupTargetSpec = Config.of({ export const remoteBackupTargetSpec = CB.Config.of({
type: Value.union( type: CB.Value.union(
{ {
name: 'Target Type', name: 'Target Type',
required: { default: 'dropbox' }, required: { default: 'dropbox' },
}, },
Variants.of({ CB.Variants.of({
dropbox: { dropbox: {
name: 'Dropbox', name: 'Dropbox',
spec: dropboxSpec, spec: dropboxSpec,
@@ -105,14 +103,14 @@ export const remoteBackupTargetSpec = Config.of({
), ),
}) })
export const diskBackupTargetSpec = Config.of({ export const diskBackupTargetSpec = CB.Config.of({
name: Value.text({ name: CB.Value.text({
name: 'Name', name: 'Name',
description: 'A friendly name for this physical target', description: 'A friendly name for this physical target',
placeholder: 'My Physical Target', placeholder: 'My Physical Target',
required: { default: null }, required: { default: null },
}), }),
path: Value.text({ path: CB.Value.text({
name: 'Path', name: 'Path',
description: 'The fully qualified path to the backup directory', description: 'The fully qualified path to the backup directory',
placeholder: 'e.g. /Backups/my-folder', placeholder: 'e.g. /Backups/my-folder',

View File

@@ -1,8 +1,8 @@
import { ValueSpecObject } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { TuiDialogOptions } from '@taiga-ui/core' import { TuiDialogOptions } from '@taiga-ui/core'
import { TuiPromptData } from '@taiga-ui/kit' import { TuiPromptData } from '@taiga-ui/kit'
export function getMarketplaceValueSpec(): ValueSpecObject { export function getMarketplaceValueSpec(): CT.ValueSpecObject {
return { return {
type: 'object', type: 'object',
name: 'Add Custom Registry', name: 'Add Custom Registry',

View File

@@ -1,15 +1,13 @@
import { Config } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/config' import { CB } from '@start9labs/start-sdk'
import { Value } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/value'
import { Variants } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/variants'
import { Proxy } from 'src/app/services/patch-db/data-model' import { Proxy } from 'src/app/services/patch-db/data-model'
import { configBuilderToSpec } from 'src/app/util/configBuilderToSpec' import { configBuilderToSpec } from 'src/app/util/configBuilderToSpec'
const auth = Config.of({ const auth = CB.Config.of({
username: Value.text({ username: CB.Value.text({
name: 'Username', name: 'Username',
required: { default: null }, required: { default: null },
}), }),
password: Value.text({ password: CB.Value.text({
name: 'Password', name: 'Password',
required: { default: null }, required: { default: null },
masked: true, masked: true,
@@ -26,7 +24,7 @@ function getStrategyUnion(proxies: Proxy[]) {
} }
}, {}) }, {})
return Value.union( return CB.Value.union(
{ {
name: 'Networking Strategy', name: 'Networking Strategy',
required: { default: null }, required: { default: null },
@@ -34,11 +32,11 @@ function getStrategyUnion(proxies: Proxy[]) {
<h5>Proxy</h5>Select this option is you prefer to hide your home/business IP address from the Internet. This option requires running your own Virtual Private Server (VPS) <i>or</i> paying service provider such as Static Wire <h5>Proxy</h5>Select this option is you prefer to hide your home/business IP address from the Internet. This option requires running your own Virtual Private Server (VPS) <i>or</i> paying service provider such as Static Wire
`, `,
}, },
Variants.of({ CB.Variants.of({
local: { local: {
name: 'Local', name: 'Local',
spec: Config.of({ spec: CB.Config.of({
ipStrategy: Value.select({ ipStrategy: CB.Value.select({
name: 'IP Strategy', name: 'IP Strategy',
description: `<h5>IPv6 Only (recommended)</h5><b>Requirements</b>:<ol><li>ISP IPv6 support</li><li>OpenWRT (recommended) or Linksys router</li></ol><b>Pros</b>: Ready for IPv6 Internet. Enhanced privacy. Run multiple clearnet servers from the same network description: `<h5>IPv6 Only (recommended)</h5><b>Requirements</b>:<ol><li>ISP IPv6 support</li><li>OpenWRT (recommended) or Linksys router</li></ol><b>Pros</b>: Ready for IPv6 Internet. Enhanced privacy. Run multiple clearnet servers from the same network
<b>Cons</b>: Interfaces using this domain will only be accessible to people whose ISP supports IPv6 <b>Cons</b>: Interfaces using this domain will only be accessible to people whose ISP supports IPv6
@@ -58,8 +56,8 @@ function getStrategyUnion(proxies: Proxy[]) {
}, },
proxy: { proxy: {
name: 'Proxy', name: 'Proxy',
spec: Config.of({ spec: CB.Config.of({
proxyId: Value.select({ proxyId: CB.Value.select({
name: 'Select Proxy', name: 'Select Proxy',
required: { default: null }, required: { default: null },
values: inboundProxies, values: inboundProxies,
@@ -72,7 +70,7 @@ function getStrategyUnion(proxies: Proxy[]) {
export function getStart9ToSpec(proxies: Proxy[]) { export function getStart9ToSpec(proxies: Proxy[]) {
return configBuilderToSpec( return configBuilderToSpec(
Config.of({ CB.Config.of({
strategy: getStrategyUnion(proxies), strategy: getStrategyUnion(proxies),
}), }),
) )
@@ -80,21 +78,21 @@ export function getStart9ToSpec(proxies: Proxy[]) {
export function getCustomSpec(proxies: Proxy[]) { export function getCustomSpec(proxies: Proxy[]) {
return configBuilderToSpec( return configBuilderToSpec(
Config.of({ CB.Config.of({
hostname: Value.text({ hostname: CB.Value.text({
name: 'Hostname', name: 'Hostname',
required: { default: null }, required: { default: null },
placeholder: 'yourdomain.com', placeholder: 'yourdomain.com',
}), }),
provider: Value.union( provider: CB.Value.union(
{ {
name: 'Dynamic DNS Provider', name: 'Dynamic DNS Provider',
required: { default: 'start9' }, required: { default: 'start9' },
}, },
Variants.of({ CB.Variants.of({
start9: { start9: {
name: 'Start9', name: 'Start9',
spec: Config.of({}), spec: CB.Config.of({}),
}, },
njalla: { njalla: {
name: 'Njalla', name: 'Njalla',

View File

@@ -17,8 +17,7 @@ import { DataModel } from 'src/app/services/patch-db/data-model'
import { ApiService } from 'src/app/services/api/embassy-api.service' import { ApiService } from 'src/app/services/api/embassy-api.service'
import { FormService } from 'src/app/services/form.service' import { FormService } from 'src/app/services/form.service'
import { EmailInfoComponent } from './info.component' import { EmailInfoComponent } from './info.component'
import { InputSpec } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT, config } from '@start9labs/start-sdk'
import { customSmtp } from '@start9labs/start-sdk/cjs/sdk/lib/config/configConstants'
@Component({ @Component({
template: ` template: `
@@ -82,7 +81,9 @@ export class SettingsEmailComponent {
private readonly api = inject(ApiService) private readonly api = inject(ApiService)
testAddress = '' testAddress = ''
readonly spec: Promise<InputSpec> = configBuilderToSpec(customSmtp) readonly spec: Promise<CT.InputSpec> = configBuilderToSpec(
config.constants.customSmtp,
)
readonly form$ = this.patch readonly form$ = this.patch
.watch$('serverInfo', 'smtp') .watch$('serverInfo', 'smtp')
.pipe( .pipe(
@@ -95,7 +96,9 @@ export class SettingsEmailComponent {
const loader = this.loader.open('Saving...').subscribe() const loader = this.loader.open('Saving...').subscribe()
try { try {
await this.api.configureEmail(customSmtp.validator.unsafeCast(value)) await this.api.configureEmail(
config.constants.customSmtp.validator.unsafeCast(value),
)
} catch (e: any) { } catch (e: any) {
this.errorService.handleError(e) this.errorService.handleError(e)
} finally { } finally {

View File

@@ -1,5 +1,4 @@
import { Config } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/config' import { CB } from '@start9labs/start-sdk'
import { Value } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/value'
import { TuiDialogOptions } from '@taiga-ui/core' import { TuiDialogOptions } from '@taiga-ui/core'
import { TuiPromptData } from '@taiga-ui/kit' import { TuiPromptData } from '@taiga-ui/kit'
@@ -13,13 +12,13 @@ export const DELETE_OPTIONS: Partial<TuiDialogOptions<TuiPromptData>> = {
}, },
} }
export const wireguardSpec = Config.of({ export const wireguardSpec = CB.Config.of({
name: Value.text({ name: CB.Value.text({
name: 'Name', name: 'Name',
description: 'A friendly name to help you remember and identify this proxy', description: 'A friendly name to help you remember and identify this proxy',
required: { default: null }, required: { default: null },
}), }),
config: Value.file({ config: CB.Value.file({
name: 'Wiregaurd Config', name: 'Wiregaurd Config',
required: { default: null }, required: { default: null },
extensions: ['.conf'], extensions: ['.conf'],

View File

@@ -24,7 +24,7 @@ import { Proxy } from 'src/app/services/patch-db/data-model'
import { ApiService } from 'src/app/services/api/embassy-api.service' import { ApiService } from 'src/app/services/api/embassy-api.service'
import { FormDialogService } from 'src/app/services/form-dialog.service' import { FormDialogService } from 'src/app/services/form-dialog.service'
import { DELETE_OPTIONS, ProxyUpdate } from './constants' import { DELETE_OPTIONS, ProxyUpdate } from './constants'
import { Value } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/value' import { CB } from '@start9labs/start-sdk'
@Component({ @Component({
selector: 'proxies-menu', selector: 'proxies-menu',
@@ -90,7 +90,7 @@ export class ProxiesMenuComponent {
async rename() { async rename() {
const spec = { name: 'Name', required: { default: this.proxy.name } } const spec = { name: 'Name', required: { default: this.proxy.name } }
const name = await Value.text(spec).build({} as any) const name = await CB.Value.text(spec).build({} as any)
const options: Partial<TuiDialogOptions<FormContext<{ name: string }>>> = { const options: Partial<TuiDialogOptions<FormContext<{ name: string }>>> = {
label: `Rename ${this.proxy.name}`, label: `Rename ${this.proxy.name}`,
data: { data: {

View File

@@ -1,12 +1,12 @@
import { Pipe, PipeTransform } from '@angular/core' import { Pipe, PipeTransform } from '@angular/core'
import { HostnameInfo } from '@start9labs/start-sdk/cjs/sdk/lib/types' import { T } from '@start9labs/start-sdk'
@Pipe({ @Pipe({
standalone: true, standalone: true,
name: 'primaryIp', name: 'primaryIp',
}) })
export class PrimaryIpPipe implements PipeTransform { export class PrimaryIpPipe implements PipeTransform {
transform(hostnames: HostnameInfo[]): string { transform(hostnames: T.HostnameInfo[]): string {
return ( return (
hostnames.map( hostnames.map(
h => h.kind === 'ip' && h.hostname.kind === 'ipv4' && h.hostname.value, h => h.kind === 'ip' && h.hostname.kind === 'ipv4' && h.hostname.value,

View File

@@ -1,4 +1,4 @@
import { ValueSpecObject } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { AvailableWifi } from 'src/app/services/api/api.types' import { AvailableWifi } from 'src/app/services/api/api.types'
import { RR } from 'src/app/services/api/api.types' import { RR } from 'src/app/services/api/api.types'
@@ -28,7 +28,7 @@ export function parseWifi(res: RR.GetWifiRes): WifiData {
} }
} }
export const wifiSpec: ValueSpecObject = { export const wifiSpec: CT.ValueSpecObject = {
type: 'object', type: 'object',
name: 'WiFi Credentials', name: 'WiFi Credentials',
description: description:

View File

@@ -1,6 +1,6 @@
import { ValueSpecObject } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
export const wifiSpec: ValueSpecObject = { export const wifiSpec: CT.ValueSpecObject = {
type: 'object', type: 'object',
name: 'WiFi Credentials', name: 'WiFi Credentials',
description: description:

View File

@@ -1,5 +1,4 @@
import { Config } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/config' import { CB } from '@start9labs/start-sdk'
import { Value } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/value'
export interface SettingBtn { export interface SettingBtn {
title: string title: string
@@ -9,22 +8,22 @@ export interface SettingBtn {
routerLink?: string routerLink?: string
} }
export const passwordSpec = Config.of({ export const passwordSpec = CB.Config.of({
currentPassword: Value.text({ currentPassword: CB.Value.text({
name: 'Current Password', name: 'Current Password',
required: { required: {
default: null, default: null,
}, },
masked: true, masked: true,
}), }),
newPassword1: Value.text({ newPassword1: CB.Value.text({
name: 'New Password', name: 'New Password',
required: { required: {
default: null, default: null,
}, },
masked: true, masked: true,
}), }),
newPassword2: Value.text({ newPassword2: CB.Value.text({
name: 'Retype New Password', name: 'Retype New Password',
required: { required: {
default: null, default: null,

View File

@@ -1,8 +1,8 @@
import { inject } from '@angular/core' import { inject } from '@angular/core'
import { FormControlComponent } from './form-control/form-control.component' import { FormControlComponent } from './form-control/form-control.component'
import { ValueSpec } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
export abstract class Control<Spec extends ValueSpec, Value> { export abstract class Control<Spec extends CT.ValueSpec, Value> {
private readonly control: FormControlComponent<Spec, Value> = private readonly control: FormControlComponent<Spec, Value> =
inject(FormControlComponent) inject(FormControlComponent)

View File

@@ -8,7 +8,7 @@ import {
tuiHeightCollapse, tuiHeightCollapse,
} from '@taiga-ui/core' } from '@taiga-ui/core'
import { TUI_PROMPT } from '@taiga-ui/kit' import { TUI_PROMPT } from '@taiga-ui/kit'
import { ValueSpecList } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { filter, takeUntil } from 'rxjs' import { filter, takeUntil } from 'rxjs'
import { FormService } from 'src/app/services/form.service' import { FormService } from 'src/app/services/form.service'
import { ERRORS } from '../form-group/form-group.component' import { ERRORS } from '../form-group/form-group.component'
@@ -22,7 +22,7 @@ import { ERRORS } from '../form-group/form-group.component'
}) })
export class FormArrayComponent { export class FormArrayComponent {
@Input({ required: true }) @Input({ required: true })
spec!: ValueSpecList spec!: CT.ValueSpecList
@HostBinding('@tuiParentStop') @HostBinding('@tuiParentStop')
readonly animation = { value: '', ...inject(TUI_ANIMATION_OPTIONS) } readonly animation = { value: '', ...inject(TUI_ANIMATION_OPTIONS) }

View File

@@ -1,5 +1,5 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { ValueSpecColor } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { Control } from '../control' import { Control } from '../control'
import { MaskitoOptions } from '@maskito/core' import { MaskitoOptions } from '@maskito/core'
@@ -8,7 +8,7 @@ import { MaskitoOptions } from '@maskito/core'
templateUrl: './form-color.component.html', templateUrl: './form-color.component.html',
styleUrls: ['./form-color.component.scss'], styleUrls: ['./form-color.component.scss'],
}) })
export class FormColorComponent extends Control<ValueSpecColor, string> { export class FormColorComponent extends Control<CT.ValueSpecColor, string> {
readonly mask: MaskitoOptions = { readonly mask: MaskitoOptions = {
mask: ['#', ...Array(6).fill(/[0-9a-f]/i)], mask: ['#', ...Array(6).fill(/[0-9a-f]/i)],
} }

View File

@@ -13,7 +13,7 @@ import {
TuiNotification, TuiNotification,
} from '@taiga-ui/core' } from '@taiga-ui/core'
import { filter, takeUntil } from 'rxjs' import { filter, takeUntil } from 'rxjs'
import { ValueSpec } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { ERRORS } from '../form-group/form-group.component' import { ERRORS } from '../form-group/form-group.component'
import { FORM_CONTROL_PROVIDERS } from './form-control.providers' import { FORM_CONTROL_PROVIDERS } from './form-control.providers'
@@ -25,7 +25,7 @@ import { FORM_CONTROL_PROVIDERS } from './form-control.providers'
providers: FORM_CONTROL_PROVIDERS, providers: FORM_CONTROL_PROVIDERS,
}) })
export class FormControlComponent< export class FormControlComponent<
T extends ValueSpec, T extends CT.ValueSpec,
V, V,
> extends AbstractTuiNullableControl<V> { > extends AbstractTuiNullableControl<V> {
@Input({ required: true }) @Input({ required: true })

View File

@@ -1,6 +1,6 @@
import { forwardRef, Provider } from '@angular/core' import { forwardRef, Provider } from '@angular/core'
import { TUI_VALIDATION_ERRORS } from '@taiga-ui/kit' import { TUI_VALIDATION_ERRORS } from '@taiga-ui/kit'
import { ValueSpec } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { FormControlComponent } from './form-control.component' import { FormControlComponent } from './form-control.component'
interface ValidatorsPatternError { interface ValidatorsPatternError {
@@ -12,7 +12,7 @@ export const FORM_CONTROL_PROVIDERS: Provider[] = [
{ {
provide: TUI_VALIDATION_ERRORS, provide: TUI_VALIDATION_ERRORS,
deps: [forwardRef(() => FormControlComponent)], deps: [forwardRef(() => FormControlComponent)],
useFactory: (control: FormControlComponent<ValueSpec, string>) => ({ useFactory: (control: FormControlComponent<CT.ValueSpec, string>) => ({
required: 'Required', required: 'Required',
pattern: ({ requiredPattern }: ValidatorsPatternError) => pattern: ({ requiredPattern }: ValidatorsPatternError) =>
('patterns' in control.spec && ('patterns' in control.spec &&

View File

@@ -6,14 +6,17 @@ import {
tuiPure, tuiPure,
TuiTime, TuiTime,
} from '@taiga-ui/cdk' } from '@taiga-ui/cdk'
import { ValueSpecDatetime } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { Control } from '../control' import { Control } from '../control'
@Component({ @Component({
selector: 'form-datetime', selector: 'form-datetime',
templateUrl: './form-datetime.component.html', templateUrl: './form-datetime.component.html',
}) })
export class FormDatetimeComponent extends Control<ValueSpecDatetime, string> { export class FormDatetimeComponent extends Control<
CT.ValueSpecDatetime,
string
> {
readonly min = TUI_FIRST_DAY readonly min = TUI_FIRST_DAY
readonly max = TUI_LAST_DAY readonly max = TUI_LAST_DAY

View File

@@ -1,6 +1,6 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { TuiFileLike } from '@taiga-ui/kit' import { TuiFileLike } from '@taiga-ui/kit'
import { ValueSpecFile } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { Control } from '../control' import { Control } from '../control'
@Component({ @Component({
@@ -8,4 +8,4 @@ import { Control } from '../control'
templateUrl: './form-file.component.html', templateUrl: './form-file.component.html',
styleUrls: ['./form-file.component.scss'], styleUrls: ['./form-file.component.scss'],
}) })
export class FormFileComponent extends Control<ValueSpecFile, TuiFileLike> {} export class FormFileComponent extends Control<CT.ValueSpecFile, TuiFileLike> {}

View File

@@ -4,7 +4,7 @@ import {
Input, Input,
ViewEncapsulation, ViewEncapsulation,
} from '@angular/core' } from '@angular/core'
import { InputSpec } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { FORM_GROUP_PROVIDERS } from './form-group.providers' import { FORM_GROUP_PROVIDERS } from './form-group.providers'
export const ERRORS = [ export const ERRORS = [
@@ -27,7 +27,7 @@ export const ERRORS = [
viewProviders: [FORM_GROUP_PROVIDERS], viewProviders: [FORM_GROUP_PROVIDERS],
}) })
export class FormGroupComponent { export class FormGroupComponent {
@Input() spec: InputSpec = {} @Input() spec: CT.InputSpec = {}
asIsOrder() { asIsOrder() {
return 0 return 0

View File

@@ -1,5 +1,5 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { ValueSpecMultiselect } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { Control } from '../control' import { Control } from '../control'
import { tuiPure } from '@taiga-ui/cdk' import { tuiPure } from '@taiga-ui/cdk'
import { invert } from '@start9labs/shared' import { invert } from '@start9labs/shared'
@@ -9,7 +9,7 @@ import { invert } from '@start9labs/shared'
templateUrl: './form-multiselect.component.html', templateUrl: './form-multiselect.component.html',
}) })
export class FormMultiselectComponent extends Control< export class FormMultiselectComponent extends Control<
ValueSpecMultiselect, CT.ValueSpecMultiselect,
readonly string[] readonly string[]
> { > {
private readonly inverted = invert(this.spec.values) private readonly inverted = invert(this.spec.values)

View File

@@ -1,11 +1,11 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { ValueSpecNumber } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { Control } from '../control' import { Control } from '../control'
@Component({ @Component({
selector: 'form-number', selector: 'form-number',
templateUrl: './form-number.component.html', templateUrl: './form-number.component.html',
}) })
export class FormNumberComponent extends Control<ValueSpecNumber, number> { export class FormNumberComponent extends Control<CT.ValueSpecNumber, number> {
protected readonly Infinity = Infinity protected readonly Infinity = Infinity
} }

View File

@@ -7,7 +7,7 @@ import {
Output, Output,
} from '@angular/core' } from '@angular/core'
import { ControlContainer } from '@angular/forms' import { ControlContainer } from '@angular/forms'
import { ValueSpecObject } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
@Component({ @Component({
selector: 'form-object', selector: 'form-object',
@@ -17,7 +17,7 @@ import { ValueSpecObject } from '@start9labs/start-sdk/cjs/sdk/lib/config/config
}) })
export class FormObjectComponent { export class FormObjectComponent {
@Input({ required: true }) @Input({ required: true })
spec!: ValueSpecObject spec!: CT.ValueSpecObject
@Input() @Input()
open = false open = false

View File

@@ -1,5 +1,5 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { ValueSpecSelect } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { invert } from '@start9labs/shared' import { invert } from '@start9labs/shared'
import { Control } from '../control' import { Control } from '../control'
@@ -7,7 +7,7 @@ import { Control } from '../control'
selector: 'form-select', selector: 'form-select',
templateUrl: './form-select.component.html', templateUrl: './form-select.component.html',
}) })
export class FormSelectComponent extends Control<ValueSpecSelect, string> { export class FormSelectComponent extends Control<CT.ValueSpecSelect, string> {
private readonly inverted = invert(this.spec.values) private readonly inverted = invert(this.spec.values)
readonly items = Object.values(this.spec.values) readonly items = Object.values(this.spec.values)

View File

@@ -1,5 +1,5 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { ValueSpecText } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { Control } from '../control' import { Control } from '../control'
import { getDefaultString } from 'src/app/util/config-utilities' import { getDefaultString } from 'src/app/util/config-utilities'
@@ -8,7 +8,7 @@ import { getDefaultString } from 'src/app/util/config-utilities'
templateUrl: './form-text.component.html', templateUrl: './form-text.component.html',
styleUrls: ['./form-text.component.scss'], styleUrls: ['./form-text.component.scss'],
}) })
export class FormTextComponent extends Control<ValueSpecText, string> { export class FormTextComponent extends Control<CT.ValueSpecText, string> {
masked = true masked = true
generate() { generate() {

View File

@@ -1,9 +1,12 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { ValueSpecTextarea } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { Control } from '../control' import { Control } from '../control'
@Component({ @Component({
selector: 'form-textarea', selector: 'form-textarea',
templateUrl: './form-textarea.component.html', templateUrl: './form-textarea.component.html',
}) })
export class FormTextareaComponent extends Control<ValueSpecTextarea, string> {} export class FormTextareaComponent extends Control<
CT.ValueSpecTextarea,
string
> {}

View File

@@ -1,5 +1,5 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { ValueSpecToggle } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
import { Control } from '../control' import { Control } from '../control'
@Component({ @Component({
@@ -7,4 +7,4 @@ import { Control } from '../control'
templateUrl: './form-toggle.component.html', templateUrl: './form-toggle.component.html',
host: { class: 'g-toggle' }, host: { class: 'g-toggle' },
}) })
export class FormToggleComponent extends Control<ValueSpecToggle, boolean> {} export class FormToggleComponent extends Control<CT.ValueSpecToggle, boolean> {}

View File

@@ -6,12 +6,7 @@ import {
OnChanges, OnChanges,
} from '@angular/core' } from '@angular/core'
import { ControlContainer, FormGroupName } from '@angular/forms' import { ControlContainer, FormGroupName } from '@angular/forms'
import { import { CT } from '@start9labs/start-sdk'
unionSelectKey,
unionValueKey,
ValueSpecSelect,
ValueSpecUnion,
} from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes'
import { FormService } from 'src/app/services/form.service' import { FormService } from 'src/app/services/form.service'
import { tuiPure } from '@taiga-ui/cdk' import { tuiPure } from '@taiga-ui/cdk'
@@ -29,24 +24,24 @@ import { tuiPure } from '@taiga-ui/cdk'
}) })
export class FormUnionComponent implements OnChanges { export class FormUnionComponent implements OnChanges {
@Input({ required: true }) @Input({ required: true })
spec!: ValueSpecUnion spec!: CT.ValueSpecUnion
selectSpec!: ValueSpecSelect selectSpec!: CT.ValueSpecSelect
readonly select = unionSelectKey readonly select = CT.unionSelectKey
readonly value = unionValueKey readonly value = CT.unionValueKey
private readonly form = inject(FormGroupName) private readonly form = inject(FormGroupName)
private readonly formService = inject(FormService) private readonly formService = inject(FormService)
get union(): string { get union(): string {
return this.form.value[unionSelectKey] return this.form.value[CT.unionSelectKey]
} }
@tuiPure @tuiPure
onUnion(union: string) { onUnion(union: string) {
this.form.control.setControl( this.form.control.setControl(
unionValueKey, CT.unionValueKey,
this.formService.getFormGroup( this.formService.getFormGroup(
union ? this.spec.variants[union].spec : {}, union ? this.spec.variants[union].spec : {},
), ),

View File

@@ -1,11 +1,11 @@
import { Pipe, PipeTransform } from '@angular/core' import { Pipe, PipeTransform } from '@angular/core'
import { ValueSpec } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
@Pipe({ @Pipe({
name: 'hint', name: 'hint',
}) })
export class HintPipe implements PipeTransform { export class HintPipe implements PipeTransform {
transform(spec: ValueSpec): string { transform(spec: CT.ValueSpec): string {
const hint = [] const hint = []
if (spec.description) { if (spec.description) {

View File

@@ -19,11 +19,8 @@ import {
} from '@start9labs/marketplace' } from '@start9labs/marketplace'
import { Log } from '@start9labs/shared' import { Log } from '@start9labs/shared'
import { configBuilderToSpec } from 'src/app/util/configBuilderToSpec' import { configBuilderToSpec } from 'src/app/util/configBuilderToSpec'
import { Config } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/config' import { CT } from '@start9labs/start-sdk'
import { Value } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/value' import { CB } from '@start9labs/start-sdk'
import { Variants } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/variants'
import { List } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/list'
import { unionSelectKey } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes'
export module Mock { export module Mock {
export const ServerUpdated: ServerStatusInfo = { export const ServerUpdated: ServerStatusInfo = {
@@ -715,27 +712,27 @@ export module Mock {
RR.GetPackageConfigRes['spec'] RR.GetPackageConfigRes['spec']
> => > =>
configBuilderToSpec( configBuilderToSpec(
Config.of({ CB.Config.of({
bitcoin: Value.object( bitcoin: CB.Value.object(
{ {
name: 'Bitcoin Settings', name: 'Bitcoin Settings',
description: description:
'RPC and P2P interface configuration options for Bitcoin Core', 'RPC and P2P interface configuration options for Bitcoin Core',
}, },
Config.of({ CB.Config.of({
'bitcoind-p2p': Value.union( 'bitcoind-p2p': CB.Value.union(
{ {
name: 'P2P Settings', name: 'P2P Settings',
description: description:
'<p>The Bitcoin Core node to connect to over the peer-to-peer (P2P) interface:</p><ul><li><strong>Bitcoin Core</strong>: The Bitcoin Core service installed on this device</li><li><strong>External Node</strong>: A Bitcoin node running on a different device</li></ul>', '<p>The Bitcoin Core node to connect to over the peer-to-peer (P2P) interface:</p><ul><li><strong>Bitcoin Core</strong>: The Bitcoin Core service installed on this device</li><li><strong>External Node</strong>: A Bitcoin node running on a different device</li></ul>',
required: { default: 'internal' }, required: { default: 'internal' },
}, },
Variants.of({ CB.Variants.of({
internal: { name: 'Bitcoin Core', spec: Config.of({}) }, internal: { name: 'Bitcoin Core', spec: CB.Config.of({}) },
external: { external: {
name: 'External Node', name: 'External Node',
spec: Config.of({ spec: CB.Config.of({
'p2p-host': Value.text({ 'p2p-host': CB.Value.text({
name: 'Public Address', name: 'Public Address',
required: { required: {
default: null, default: null,
@@ -743,7 +740,7 @@ export module Mock {
description: description:
'The public address of your Bitcoin Core server', 'The public address of your Bitcoin Core server',
}), }),
'p2p-port': Value.number({ 'p2p-port': CB.Value.number({
name: 'P2P Port', name: 'P2P Port',
description: description:
'The port that your Bitcoin Core P2P server is bound to', 'The port that your Bitcoin Core P2P server is bound to',
@@ -760,7 +757,7 @@ export module Mock {
), ),
}), }),
), ),
users: Value.multiselect({ users: CB.Value.multiselect({
name: 'Users', name: 'Users',
default: [], default: [],
maxLength: 2, maxLength: 2,
@@ -772,21 +769,21 @@ export module Mock {
lucy: 'Lucy', lucy: 'Lucy',
}, },
}), }),
advanced: Value.object( advanced: CB.Value.object(
{ {
name: 'Advanced', name: 'Advanced',
description: 'Advanced settings', description: 'Advanced settings',
}, },
Config.of({ CB.Config.of({
rpcsettings: Value.object( rpcsettings: CB.Value.object(
{ {
name: 'RPC Settings', name: 'RPC Settings',
description: 'rpc username and password', description: 'rpc username and password',
warning: warning:
'Adding RPC users gives them special permissions on your node.', 'Adding RPC users gives them special permissions on your node.',
}, },
Config.of({ CB.Config.of({
rpcuser2: Value.text({ rpcuser2: CB.Value.text({
name: 'RPC Username', name: 'RPC Username',
required: { required: {
default: 'defaultrpcusername', default: 'defaultrpcusername',
@@ -799,7 +796,7 @@ export module Mock {
}, },
], ],
}), }),
rpcuser: Value.text({ rpcuser: CB.Value.text({
name: 'RPC Username', name: 'RPC Username',
required: { required: {
default: 'defaultrpcusername', default: 'defaultrpcusername',
@@ -812,7 +809,7 @@ export module Mock {
}, },
], ],
}), }),
rpcpass: Value.text({ rpcpass: CB.Value.text({
name: 'RPC User Password', name: 'RPC User Password',
required: { required: {
default: { default: {
@@ -822,7 +819,7 @@ export module Mock {
}, },
description: 'rpc password', description: 'rpc password',
}), }),
rpcpass2: Value.text({ rpcpass2: CB.Value.text({
name: 'RPC User Password', name: 'RPC User Password',
required: { required: {
default: { default: {
@@ -836,15 +833,15 @@ export module Mock {
), ),
}), }),
), ),
testnet: Value.toggle({ testnet: CB.Value.toggle({
name: 'Testnet', name: 'Testnet',
default: true, default: true,
description: description:
'<ul><li>determines whether your node is running on testnet or mainnet</li></ul><script src="fake"></script>', '<ul><li>determines whether your node is running on testnet or mainnet</li></ul><script src="fake"></script>',
warning: 'Chain will have to resync!', warning: 'Chain will have to resync!',
}), }),
'object-list': Value.list( 'object-list': CB.Value.list(
List.obj( CB.List.obj(
{ {
name: 'Object List', name: 'Object List',
minLength: 0, minLength: 0,
@@ -856,13 +853,13 @@ export module Mock {
description: 'This is a list of objects, like users or something', description: 'This is a list of objects, like users or something',
}, },
{ {
spec: Config.of({ spec: CB.Config.of({
'first-name': Value.text({ 'first-name': CB.Value.text({
name: 'First Name', name: 'First Name',
required: false, required: false,
description: 'User first name', description: 'User first name',
}), }),
'last-name': Value.text({ 'last-name': CB.Value.text({
name: 'Last Name', name: 'Last Name',
required: { required: {
default: { default: {
@@ -878,7 +875,7 @@ export module Mock {
}, },
], ],
}), }),
age: Value.number({ age: CB.Value.number({
name: 'Age', name: 'Age',
description: 'The age of the user', description: 'The age of the user',
warning: 'User must be at least 18.', warning: 'User must be at least 18.',
@@ -887,13 +884,13 @@ export module Mock {
integer: false, integer: false,
}), }),
}), }),
displayAs: "I'm {{last-name}}, {{first-name}} {{last-name}}", displayAs: 'I\'m {{last-name}}, {{first-name}} {{last-name}}',
uniqueBy: 'last-name', uniqueBy: 'last-name',
}, },
), ),
), ),
'union-list': Value.list( 'union-list': CB.Value.list(
List.obj( CB.List.obj(
{ {
name: 'Union List', name: 'Union List',
minLength: 0, minLength: 0,
@@ -903,27 +900,27 @@ export module Mock {
warning: 'If you change this, things may work.', warning: 'If you change this, things may work.',
}, },
{ {
spec: Config.of({ spec: CB.Config.of({
/* TODO: Convert range for this value ([0, 2])*/ /* TODO: Convert range for this value ([0, 2])*/
union: Value.union( union: CB.Value.union(
{ {
name: 'Preference', name: 'Preference',
description: null, description: null,
warning: null, warning: null,
required: { default: 'summer' }, required: { default: 'summer' },
}, },
Variants.of({ CB.Variants.of({
summer: { summer: {
name: 'summer', name: 'summer',
spec: Config.of({ spec: CB.Config.of({
'favorite-tree': Value.text({ 'favorite-tree': CB.Value.text({
name: 'Favorite Tree', name: 'Favorite Tree',
required: { required: {
default: 'Maple', default: 'Maple',
}, },
description: 'What is your favorite tree?', description: 'What is your favorite tree?',
}), }),
'favorite-flower': Value.select({ 'favorite-flower': CB.Value.select({
name: 'Favorite Flower', name: 'Favorite Flower',
description: 'Select your favorite flower', description: 'Select your favorite flower',
required: { required: {
@@ -940,8 +937,8 @@ export module Mock {
}, },
winter: { winter: {
name: 'winter', name: 'winter',
spec: Config.of({ spec: CB.Config.of({
'like-snow': Value.toggle({ 'like-snow': CB.Value.toggle({
name: 'Like Snow?', name: 'Like Snow?',
default: true, default: true,
description: 'Do you like snow or not?', description: 'Do you like snow or not?',
@@ -955,7 +952,7 @@ export module Mock {
}, },
), ),
), ),
'random-select': Value.select({ 'random-select': CB.Value.select({
name: 'Random select', name: 'Random select',
description: 'This is not even real.', description: 'This is not even real.',
warning: 'Be careful changing this!', warning: 'Be careful changing this!',
@@ -970,7 +967,7 @@ export module Mock {
disabled: ['option2'], disabled: ['option2'],
}), }),
'favorite-number': 'favorite-number':
/* TODO: Convert range for this value ((-100,100])*/ Value.number({ /* TODO: Convert range for this value ((-100,100])*/ CB.Value.number({
name: 'Favorite Number', name: 'Favorite Number',
description: 'Your favorite number of all time', description: 'Your favorite number of all time',
warning: warning:
@@ -981,8 +978,8 @@ export module Mock {
integer: false, integer: false,
units: 'BTC', units: 'BTC',
}), }),
'unlucky-numbers': Value.list( 'unlucky-numbers': CB.Value.list(
List.number( CB.List.number(
{ {
name: 'Unlucky Numbers', name: 'Unlucky Numbers',
minLength: 0, minLength: 0,
@@ -996,34 +993,34 @@ export module Mock {
}, },
), ),
), ),
rpcsettings: Value.object( rpcsettings: CB.Value.object(
{ {
name: 'RPC Settings', name: 'RPC Settings',
description: 'rpc username and password', description: 'rpc username and password',
warning: warning:
'Adding RPC users gives them special permissions on your node.', 'Adding RPC users gives them special permissions on your node.',
}, },
Config.of({ CB.Config.of({
laws: Value.object( laws: CB.Value.object(
{ {
name: 'Laws', name: 'Laws',
description: 'the law of the realm', description: 'the law of the realm',
}, },
Config.of({ CB.Config.of({
law1: Value.text({ law1: CB.Value.text({
name: 'First Law', name: 'First Law',
required: false, required: false,
description: 'the first law', description: 'the first law',
}), }),
law2: Value.text({ law2: CB.Value.text({
name: 'Second Law', name: 'Second Law',
required: false, required: false,
description: 'the second law', description: 'the second law',
}), }),
}), }),
), ),
rulemakers: Value.list( rulemakers: CB.Value.list(
List.obj( CB.List.obj(
{ {
name: 'Rule Makers', name: 'Rule Makers',
minLength: 0, minLength: 0,
@@ -1031,8 +1028,8 @@ export module Mock {
description: 'the people who make the rules', description: 'the people who make the rules',
}, },
{ {
spec: Config.of({ spec: CB.Config.of({
rulemakername: Value.text({ rulemakername: CB.Value.text({
name: 'Rulemaker Name', name: 'Rulemaker Name',
required: { required: {
default: { default: {
@@ -1042,7 +1039,7 @@ export module Mock {
}, },
description: 'the name of the rule maker', description: 'the name of the rule maker',
}), }),
rulemakerip: Value.text({ rulemakerip: CB.Value.text({
name: 'Rulemaker IP', name: 'Rulemaker IP',
required: { required: {
default: '192.168.1.0', default: '192.168.1.0',
@@ -1060,7 +1057,7 @@ export module Mock {
}, },
), ),
), ),
rpcuser: Value.text({ rpcuser: CB.Value.text({
name: 'RPC Username', name: 'RPC Username',
required: { required: {
default: 'defaultrpcusername', default: 'defaultrpcusername',
@@ -1073,7 +1070,7 @@ export module Mock {
}, },
], ],
}), }),
rpcpass: Value.text({ rpcpass: CB.Value.text({
name: 'RPC User Password', name: 'RPC User Password',
required: { required: {
default: { default: {
@@ -1086,7 +1083,7 @@ export module Mock {
}), }),
}), }),
), ),
'bitcoin-node': Value.union( 'bitcoin-node': CB.Value.union(
{ {
name: 'Bitcoin Node', name: 'Bitcoin Node',
description: 'Options<ul><li>Item 1</li><li>Item 2</li></ul>', description: 'Options<ul><li>Item 1</li><li>Item 2</li></ul>',
@@ -1094,25 +1091,25 @@ export module Mock {
required: { default: 'internal' }, required: { default: 'internal' },
disabled: ['fake'], disabled: ['fake'],
}, },
Variants.of({ CB.Variants.of({
fake: { fake: {
name: 'Fake', name: 'Fake',
spec: Config.of({}), spec: CB.Config.of({}),
}, },
internal: { internal: {
name: 'Internal', name: 'Internal',
spec: Config.of({}), spec: CB.Config.of({}),
}, },
external: { external: {
name: 'External', name: 'External',
spec: Config.of({ spec: CB.Config.of({
'emergency-contact': Value.object( 'emergency-contact': CB.Value.object(
{ {
name: 'Emergency Contact', name: 'Emergency Contact',
description: 'The person to contact in case of emergency.', description: 'The person to contact in case of emergency.',
}, },
Config.of({ CB.Config.of({
name: Value.text({ name: CB.Value.text({
name: 'Name', name: 'Name',
required: { required: {
default: null, default: null,
@@ -1124,7 +1121,7 @@ export module Mock {
}, },
], ],
}), }),
email: Value.text({ email: CB.Value.text({
name: 'Email', name: 'Email',
inputmode: 'email', inputmode: 'email',
required: { required: {
@@ -1133,7 +1130,7 @@ export module Mock {
}), }),
}), }),
), ),
'public-domain': Value.text({ 'public-domain': CB.Value.text({
name: 'Public Domain', name: 'Public Domain',
required: { required: {
default: 'bitcoinnode.com', default: 'bitcoinnode.com',
@@ -1146,7 +1143,7 @@ export module Mock {
}, },
], ],
}), }),
'private-domain': Value.text({ 'private-domain': CB.Value.text({
name: 'Private Domain', name: 'Private Domain',
required: { required: {
default: null, default: null,
@@ -1159,7 +1156,7 @@ export module Mock {
}, },
}), }),
), ),
port: Value.number({ port: CB.Value.number({
name: 'Port', name: 'Port',
description: description:
'the default port for your Bitcoin node. default: 8333, testnet: 18333, regtest: 18444', 'the default port for your Bitcoin node. default: 8333, testnet: 18333, regtest: 18444',
@@ -1171,7 +1168,7 @@ export module Mock {
step: 1, step: 1,
integer: true, integer: true,
}), }),
'favorite-slogan': Value.text({ 'favorite-slogan': CB.Value.text({
name: 'Favorite Slogan', name: 'Favorite Slogan',
generate: { generate: {
charset: 'a-z,A-Z,2-9', charset: 'a-z,A-Z,2-9',
@@ -1182,8 +1179,8 @@ export module Mock {
'You most favorite slogan in the whole world, used for paying you.', 'You most favorite slogan in the whole world, used for paying you.',
masked: true, masked: true,
}), }),
rpcallowip: Value.list( rpcallowip: CB.Value.list(
List.text( CB.List.text(
{ {
name: 'RPC Allowed IPs', name: 'RPC Allowed IPs',
minLength: 1, minLength: 1,
@@ -1205,8 +1202,8 @@ export module Mock {
}, },
), ),
), ),
rpcauth: Value.list( rpcauth: CB.Value.list(
List.text( CB.List.text(
{ {
name: 'RPC Auth', name: 'RPC Auth',
description: description:
@@ -1251,7 +1248,7 @@ export module Mock {
rulemakers: [], rulemakers: [],
}, },
'bitcoin-node': { 'bitcoin-node': {
[unionSelectKey]: 'internal', [CT.unionSelectKey]: 'internal',
}, },
port: 20, port: 20,
rpcallowip: undefined, rpcallowip: undefined,

View File

@@ -13,8 +13,8 @@ import {
FollowLogsRes, FollowLogsRes,
FollowLogsReq, FollowLogsReq,
} from '@start9labs/shared' } from '@start9labs/shared'
import { customSmtp } from '@start9labs/start-sdk/cjs/sdk/lib/config/configConstants' import { CT } from '@start9labs/start-sdk'
import { InputSpec } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { config } from '@start9labs/start-sdk'
export module RR { export module RR {
// DB // DB
@@ -205,7 +205,8 @@ export module RR {
// email // email
export type ConfigureEmailReq = typeof customSmtp.validator._TYPE // email.configure export type ConfigureEmailReq =
typeof config.constants.customSmtp.validator._TYPE // email.configure
export type ConfigureEmailRes = null export type ConfigureEmailRes = null
export type TestEmailReq = ConfigureEmailReq & { to: string } // email.test export type TestEmailReq = ConfigureEmailReq & { to: string } // email.test
@@ -319,7 +320,7 @@ export module RR {
export type InstallPackageRes = null export type InstallPackageRes = null
export type GetPackageConfigReq = { id: string } // package.config.get export type GetPackageConfigReq = { id: string } // package.config.get
export type GetPackageConfigRes = { spec: InputSpec; config: object } export type GetPackageConfigRes = { spec: CT.InputSpec; config: object }
export type DrySetPackageConfigReq = { id: string; config: object } // package.config.set.dry export type DrySetPackageConfigReq = { id: string; config: object } // package.config.set.dry
export type DrySetPackageConfigRes = Breakages export type DrySetPackageConfigRes = Breakages
@@ -361,7 +362,7 @@ export module RR {
export type DryConfigureDependencyRes = { export type DryConfigureDependencyRes = {
oldConfig: object oldConfig: object
newConfig: object newConfig: object
spec: InputSpec spec: CT.InputSpec
} }
export type SideloadPackageReq = { export type SideloadPackageReq = {

View File

@@ -8,29 +8,7 @@ import {
Validators, Validators,
} from '@angular/forms' } from '@angular/forms'
import { getDefaultString } from '../util/config-utilities' import { getDefaultString } from '../util/config-utilities'
import { import { CT } from '@start9labs/start-sdk'
InputSpec,
ListValueSpecNumber,
ListValueSpecObject,
ListValueSpecOf,
ListValueSpecText,
UniqueBy,
ValueSpec,
ValueSpecSelect,
ValueSpecMultiselect,
ValueSpecFile,
ValueSpecList,
ValueSpecNumber,
ValueSpecObject,
ValueSpecText,
ValueSpecUnion,
ValueSpecTextarea,
ValueSpecColor,
ValueSpecDatetime,
unionSelectKey,
unionValueKey,
isValueSpecListOf,
} from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes'
const Mustache = require('mustache') const Mustache = require('mustache')
@Injectable({ @Injectable({
@@ -40,16 +18,16 @@ export class FormService {
constructor(private readonly formBuilder: UntypedFormBuilder) {} constructor(private readonly formBuilder: UntypedFormBuilder) {}
createForm( createForm(
spec: InputSpec, spec: CT.InputSpec,
current: Record<string, any> = {}, current: Record<string, any> = {},
): UntypedFormGroup { ): UntypedFormGroup {
return this.getFormGroup(spec, [], current) return this.getFormGroup(spec, [], current)
} }
getUnionSelectSpec( getUnionSelectSpec(
spec: ValueSpecUnion, spec: CT.ValueSpecUnion,
selection: string | null, selection: string | null,
): ValueSpecSelect { ): CT.ValueSpecSelect {
return { return {
...spec, ...spec,
type: 'select', type: 'select',
@@ -61,34 +39,34 @@ export class FormService {
} }
getUnionObject( getUnionObject(
spec: ValueSpecUnion, spec: CT.ValueSpecUnion,
selection: string | null, selection: string | null,
): UntypedFormGroup { ): UntypedFormGroup {
const group = this.getFormGroup({ const group = this.getFormGroup({
[unionSelectKey]: this.getUnionSelectSpec(spec, selection), [CT.unionSelectKey]: this.getUnionSelectSpec(spec, selection),
}) })
group.setControl( group.setControl(
unionValueKey, CT.unionValueKey,
this.getFormGroup(selection ? spec.variants[selection].spec : {}), this.getFormGroup(selection ? spec.variants[selection].spec : {}),
) )
return group return group
} }
getListItem(spec: ValueSpecList, entry?: any) { getListItem(spec: CT.ValueSpecList, entry?: any) {
const listItemValidators = getListItemValidators(spec) const listItemValidators = getListItemValidators(spec)
if (isValueSpecListOf(spec, 'text')) { if (CT.isValueSpecListOf(spec, 'text')) {
return this.formBuilder.control(entry, listItemValidators) return this.formBuilder.control(entry, listItemValidators)
} else if (isValueSpecListOf(spec, 'number')) { } else if (CT.isValueSpecListOf(spec, 'number')) {
return this.formBuilder.control(entry, listItemValidators) return this.formBuilder.control(entry, listItemValidators)
} else if (isValueSpecListOf(spec, 'object')) { } else if (CT.isValueSpecListOf(spec, 'object')) {
return this.getFormGroup(spec.spec.spec, listItemValidators, entry) return this.getFormGroup(spec.spec.spec, listItemValidators, entry)
} }
} }
getFormGroup( getFormGroup(
config: InputSpec, config: CT.InputSpec,
validators: ValidatorFn[] = [], validators: ValidatorFn[] = [],
current?: Record<string, any> | null, current?: Record<string, any> | null,
): UntypedFormGroup { ): UntypedFormGroup {
@@ -103,7 +81,7 @@ export class FormService {
} }
private getFormEntry( private getFormEntry(
spec: ValueSpec, spec: CT.ValueSpec,
currentValue?: any, currentValue?: any,
): UntypedFormGroup | UntypedFormArray | UntypedFormControl { ): UntypedFormGroup | UntypedFormArray | UntypedFormControl {
let value: any let value: any
@@ -154,7 +132,7 @@ export class FormService {
fileValidators(spec), fileValidators(spec),
) )
case 'union': case 'union':
const currentSelection = currentValue?.[unionSelectKey] const currentSelection = currentValue?.[CT.unionSelectKey]
const isValid = !!spec.variants[currentSelection] const isValid = !!spec.variants[currentSelection]
return this.getUnionObject( return this.getUnionObject(
@@ -176,20 +154,20 @@ export class FormService {
} }
} }
function getListItemValidators(spec: ValueSpecList) { function getListItemValidators(spec: CT.ValueSpecList) {
if (isValueSpecListOf(spec, 'text')) { if (CT.isValueSpecListOf(spec, 'text')) {
return stringValidators(spec.spec) return stringValidators(spec.spec)
} else if (isValueSpecListOf(spec, 'number')) { } else if (CT.isValueSpecListOf(spec, 'number')) {
return numberValidators(spec.spec) return numberValidators(spec.spec)
} }
} }
function stringValidators( function stringValidators(
spec: ValueSpecText | ListValueSpecText, spec: CT.ValueSpecText | CT.ListValueSpecText,
): ValidatorFn[] { ): ValidatorFn[] {
const validators: ValidatorFn[] = [] const validators: ValidatorFn[] = []
if ((spec as ValueSpecText).required) { if ((spec as CT.ValueSpecText).required) {
validators.push(Validators.required) validators.push(Validators.required)
} }
@@ -202,7 +180,7 @@ function stringValidators(
return validators return validators
} }
function textareaValidators(spec: ValueSpecTextarea): ValidatorFn[] { function textareaValidators(spec: CT.ValueSpecTextarea): ValidatorFn[] {
const validators: ValidatorFn[] = [] const validators: ValidatorFn[] = []
if (spec.required) { if (spec.required) {
@@ -214,7 +192,7 @@ function textareaValidators(spec: ValueSpecTextarea): ValidatorFn[] {
return validators return validators
} }
function colorValidators({ required }: ValueSpecColor): ValidatorFn[] { function colorValidators({ required }: CT.ValueSpecColor): ValidatorFn[] {
const validators: ValidatorFn[] = [Validators.pattern(/^#[0-9a-f]{6}$/i)] const validators: ValidatorFn[] = [Validators.pattern(/^#[0-9a-f]{6}$/i)]
if (required) { if (required) {
@@ -228,7 +206,7 @@ function datetimeValidators({
required, required,
min, min,
max, max,
}: ValueSpecDatetime): ValidatorFn[] { }: CT.ValueSpecDatetime): ValidatorFn[] {
const validators: ValidatorFn[] = [] const validators: ValidatorFn[] = []
if (required) { if (required) {
@@ -247,13 +225,13 @@ function datetimeValidators({
} }
function numberValidators( function numberValidators(
spec: ValueSpecNumber | ListValueSpecNumber, spec: CT.ValueSpecNumber | CT.ListValueSpecNumber,
): ValidatorFn[] { ): ValidatorFn[] {
const validators: ValidatorFn[] = [] const validators: ValidatorFn[] = []
validators.push(isNumber()) validators.push(isNumber())
if ((spec as ValueSpecNumber).required) { if ((spec as CT.ValueSpecNumber).required) {
validators.push(Validators.required) validators.push(Validators.required)
} }
@@ -266,7 +244,7 @@ function numberValidators(
return validators return validators
} }
function selectValidators(spec: ValueSpecSelect): ValidatorFn[] { function selectValidators(spec: CT.ValueSpecSelect): ValidatorFn[] {
const validators: ValidatorFn[] = [] const validators: ValidatorFn[] = []
if (spec.required) { if (spec.required) {
@@ -276,20 +254,20 @@ function selectValidators(spec: ValueSpecSelect): ValidatorFn[] {
return validators return validators
} }
function multiselectValidators(spec: ValueSpecMultiselect): ValidatorFn[] { function multiselectValidators(spec: CT.ValueSpecMultiselect): ValidatorFn[] {
const validators: ValidatorFn[] = [] const validators: ValidatorFn[] = []
validators.push(listInRange(spec.minLength, spec.maxLength)) validators.push(listInRange(spec.minLength, spec.maxLength))
return validators return validators
} }
function listValidators(spec: ValueSpecList): ValidatorFn[] { function listValidators(spec: CT.ValueSpecList): ValidatorFn[] {
const validators: ValidatorFn[] = [] const validators: ValidatorFn[] = []
validators.push(listInRange(spec.minLength, spec.maxLength)) validators.push(listInRange(spec.minLength, spec.maxLength))
validators.push(listItemIssue()) validators.push(listItemIssue())
return validators return validators
} }
function fileValidators(spec: ValueSpecFile): ValidatorFn[] { function fileValidators(spec: CT.ValueSpecFile): ValidatorFn[] {
const validators: ValidatorFn[] = [] const validators: ValidatorFn[] = []
if (spec.required) { if (spec.required) {
@@ -397,7 +375,7 @@ export function listItemIssue(): ValidatorFn {
} }
} }
export function listUnique(spec: ValueSpecList): ValidatorFn { export function listUnique(spec: CT.ValueSpecList): ValidatorFn {
return control => { return control => {
const list = control.value const list = control.value
for (let idx = 0; idx < list.length; idx++) { for (let idx = 0; idx < list.length; idx++) {
@@ -407,7 +385,7 @@ export function listUnique(spec: ValueSpecList): ValidatorFn {
let display1: string let display1: string
let display2: string let display2: string
let uniqueMessage = isObject(objSpec) let uniqueMessage = isObject(objSpec)
? uniqueByMessageWrapper(objSpec.uniqueBy, objSpec, list[idx]) ? uniqueByMessageWrapper(objSpec.uniqueBy, objSpec)
: '' : ''
if (isObject(objSpec) && objSpec.displayAs) { if (isObject(objSpec) && objSpec.displayAs) {
@@ -434,7 +412,7 @@ export function listUnique(spec: ValueSpecList): ValidatorFn {
} }
} }
function listItemEquals(spec: ValueSpecList, val1: any, val2: any): boolean { function listItemEquals(spec: CT.ValueSpecList, val1: any, val2: any): boolean {
// TODO: fix types // TODO: fix types
switch (spec.spec.type) { switch (spec.spec.type) {
case 'text': case 'text':
@@ -448,7 +426,7 @@ function listItemEquals(spec: ValueSpecList, val1: any, val2: any): boolean {
} }
} }
function itemEquals(spec: ValueSpec, val1: any, val2: any): boolean { function itemEquals(spec: CT.ValueSpec, val1: any, val2: any): boolean {
switch (spec.type) { switch (spec.type) {
case 'text': case 'text':
case 'textarea': case 'textarea':
@@ -460,15 +438,15 @@ function itemEquals(spec: ValueSpec, val1: any, val2: any): boolean {
// TODO: 'unique-by' does not exist on ValueSpecObject, fix types // TODO: 'unique-by' does not exist on ValueSpecObject, fix types
return objEquals( return objEquals(
(spec as any)['unique-by'], (spec as any)['unique-by'],
spec as ValueSpecObject, spec as CT.ValueSpecObject,
val1, val1,
val2, val2,
) )
case 'union': case 'union':
// TODO: 'unique-by' does not exist on ValueSpecUnion, fix types // TODO: 'unique-by' does not exist on CT.ValueSpecUnion, fix types
return unionEquals( return unionEquals(
(spec as any)['unique-by'], (spec as any)['unique-by'],
spec as ValueSpecUnion, spec as CT.ValueSpecUnion,
val1, val1,
val2, val2,
) )
@@ -488,8 +466,8 @@ function itemEquals(spec: ValueSpec, val1: any, val2: any): boolean {
} }
function listObjEquals( function listObjEquals(
uniqueBy: UniqueBy, uniqueBy: CT.UniqueBy,
spec: ListValueSpecObject, spec: CT.ListValueSpecObject,
val1: any, val1: any,
val2: any, val2: any,
): boolean { ): boolean {
@@ -516,8 +494,8 @@ function listObjEquals(
} }
function objEquals( function objEquals(
uniqueBy: UniqueBy, uniqueBy: CT.UniqueBy,
spec: ValueSpecObject, spec: CT.ValueSpecObject,
val1: any, val1: any,
val2: any, val2: any,
): boolean { ): boolean {
@@ -545,17 +523,17 @@ function objEquals(
} }
function unionEquals( function unionEquals(
uniqueBy: UniqueBy, uniqueBy: CT.UniqueBy,
spec: ValueSpecUnion, spec: CT.ValueSpecUnion,
val1: any, val1: any,
val2: any, val2: any,
): boolean { ): boolean {
const variantSpec = spec.variants[val1[unionSelectKey]].spec const variantSpec = spec.variants[val1[CT.unionSelectKey]].spec
if (!uniqueBy) { if (!uniqueBy) {
return false return false
} else if (typeof uniqueBy === 'string') { } else if (typeof uniqueBy === 'string') {
if (uniqueBy === unionSelectKey) { if (uniqueBy === CT.unionSelectKey) {
return val1[unionSelectKey] === val2[unionSelectKey] return val1[CT.unionSelectKey] === val2[CT.unionSelectKey]
} else { } else {
return itemEquals(variantSpec[uniqueBy], val1[uniqueBy], val2[uniqueBy]) return itemEquals(variantSpec[uniqueBy], val1[uniqueBy], val2[uniqueBy])
} }
@@ -578,9 +556,8 @@ function unionEquals(
} }
function uniqueByMessageWrapper( function uniqueByMessageWrapper(
uniqueBy: UniqueBy, uniqueBy: CT.UniqueBy,
spec: ListValueSpecObject, spec: CT.ListValueSpecObject,
obj: Record<string, string>,
) { ) {
let configSpec = spec.spec let configSpec = spec.spec
@@ -591,8 +568,8 @@ function uniqueByMessageWrapper(
} }
function uniqueByMessage( function uniqueByMessage(
uniqueBy: UniqueBy, uniqueBy: CT.UniqueBy,
configSpec: InputSpec, configSpec: CT.InputSpec,
outermost = true, outermost = true,
): string { ): string {
let joinFunc let joinFunc
@@ -601,7 +578,7 @@ function uniqueByMessage(
return '' return ''
} else if (typeof uniqueBy === 'string') { } else if (typeof uniqueBy === 'string') {
return configSpec[uniqueBy] return configSpec[uniqueBy]
? (configSpec[uniqueBy] as ValueSpecObject).name ? (configSpec[uniqueBy] as CT.ValueSpecObject).name
: uniqueBy : uniqueBy
} else if ('any' in uniqueBy) { } else if ('any' in uniqueBy) {
joinFunc = ' OR ' joinFunc = ' OR '
@@ -620,13 +597,15 @@ function uniqueByMessage(
: '(' + ret + ')' : '(' + ret + ')'
} }
function isObject(spec: ListValueSpecOf<any>): spec is ListValueSpecObject { function isObject(
spec: CT.ListValueSpecOf<any>,
): spec is CT.ListValueSpecObject {
// only lists of objects have uniqueBy // only lists of objects have uniqueBy
return 'uniqueBy' in spec return 'uniqueBy' in spec
} }
export function convertValuesRecursive( export function convertValuesRecursive(
configSpec: InputSpec, configSpec: CT.InputSpec,
group: UntypedFormGroup, group: UntypedFormGroup,
) { ) {
Object.entries(configSpec).forEach(([key, valueSpec]) => { Object.entries(configSpec).forEach(([key, valueSpec]) => {
@@ -645,7 +624,7 @@ export function convertValuesRecursive(
} else if (valueSpec.type === 'union') { } else if (valueSpec.type === 'union') {
const formGr = group.get(key) as UntypedFormGroup const formGr = group.get(key) as UntypedFormGroup
const spec = const spec =
valueSpec.variants[formGr.controls[unionSelectKey].value].spec valueSpec.variants[formGr.controls[CT.unionSelectKey].value].spec
convertValuesRecursive(spec, formGr) convertValuesRecursive(spec, formGr)
} else if (valueSpec.type === 'list') { } else if (valueSpec.type === 'list') {
const formArr = group.get(key) as UntypedFormArray const formArr = group.get(key) as UntypedFormArray
@@ -661,7 +640,7 @@ export function convertValuesRecursive(
}) })
} else if (valueSpec.spec.type === 'object') { } else if (valueSpec.spec.type === 'object') {
controls.forEach(formGroup => { controls.forEach(formGroup => {
const objectSpec = valueSpec.spec as ListValueSpecObject const objectSpec = valueSpec.spec as CT.ListValueSpecObject
convertValuesRecursive(objectSpec.spec, formGroup as UntypedFormGroup) convertValuesRecursive(objectSpec.spec, formGroup as UntypedFormGroup)
}) })
} }

View File

@@ -2,11 +2,7 @@ import { BackupJob, ServerNotifications } from '../api/api.types'
import { Url } from '@start9labs/shared' import { Url } from '@start9labs/shared'
import { Manifest } from '@start9labs/marketplace' import { Manifest } from '@start9labs/marketplace'
import { T } from '@start9labs/start-sdk' import { T } from '@start9labs/start-sdk'
import { import { config } from '@start9labs/start-sdk'
ActionMetadata,
HostnameInfo,
} from '@start9labs/start-sdk/cjs/sdk/lib/types'
import { customSmtp } from '@start9labs/start-sdk/cjs/sdk/lib/config/configConstants'
export interface DataModel { export interface DataModel {
serverInfo: ServerInfo serverInfo: ServerInfo
@@ -59,7 +55,7 @@ export interface ServerInfo {
id: string id: string
version: string version: string
country: string country: string
ui: HostnameInfo[] ui: T.HostnameInfo[]
network: NetworkInfo network: NetworkInfo
lastBackup: string | null lastBackup: string | null
unreadNotifications: { unreadNotifications: {
@@ -71,7 +67,7 @@ export interface ServerInfo {
pubkey: string pubkey: string
caFingerprint: string caFingerprint: string
ntpSynced: boolean ntpSynced: boolean
smtp: typeof customSmtp.validator._TYPE smtp: typeof config.constants.customSmtp.validator._TYPE
passwordHash: string passwordHash: string
platform: string platform: string
} }
@@ -156,7 +152,7 @@ export type PackageDataEntry<T extends StateInfo = StateInfo> = {
stateInfo: T stateInfo: T
icon: Url icon: Url
status: Status status: Status
actions: Record<string, ActionMetadata> actions: Record<string, T.ActionMetadata>
lastBackup: string | null lastBackup: string | null
currentDependencies: { [id: string]: CurrentDependencyInfo } currentDependencies: { [id: string]: CurrentDependencyInfo }
dependencyInfo: { dependencyInfo: {

View File

@@ -11,8 +11,7 @@ import { FormDialogService } from 'src/app/services/form-dialog.service'
import { configBuilderToSpec } from 'src/app/util/configBuilderToSpec' import { configBuilderToSpec } from 'src/app/util/configBuilderToSpec'
import { ApiService } from './api/embassy-api.service' import { ApiService } from './api/embassy-api.service'
import { DataModel } from './patch-db/data-model' import { DataModel } from './patch-db/data-model'
import { Config } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/config' import { CB } from '@start9labs/start-sdk'
import { Value } from '@start9labs/start-sdk/cjs/sdk/lib/config/builder/value'
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
@@ -30,14 +29,12 @@ export class ProxyService {
const network = await firstValueFrom( const network = await firstValueFrom(
this.patch.watch$('serverInfo', 'network'), this.patch.watch$('serverInfo', 'network'),
) )
const config = Config.of({ const config = CB.Config.of({
proxyId: Value.select({ proxyId: CB.Value.select({
name: 'Select Proxy', name: 'Select Proxy',
required: { default: current }, required: { default: current },
values: network.proxies values: network.proxies
.filter( .filter(p => p.type === 'outbound' || p.type === 'inbound-outbound')
p => p.type === 'outbound' || p.type === 'inbound-outbound',
)
.reduce((prev, curr) => { .reduce((prev, curr) => {
return { return {
[curr.id]: curr.name, [curr.id]: curr.name,
@@ -71,10 +68,7 @@ export class ProxyService {
this.formDialog.open(FormComponent, options) this.formDialog.open(FormComponent, options)
} }
private async saveOutboundProxy( private async saveOutboundProxy(proxy: string | null, packageId?: string) {
proxy: string | null,
packageId?: string,
) {
const loader = this.loader.open(`Saving`).subscribe() const loader = this.loader.open(`Saving`).subscribe()
try { try {

View File

@@ -1,4 +1,4 @@
import { DefaultString } from '@start9labs/start-sdk/cjs/sdk/lib/config/configTypes' import { CT } from '@start9labs/start-sdk'
export class Range { export class Range {
min?: number min?: number
@@ -48,7 +48,7 @@ export class Range {
} }
} }
export function getDefaultString(defaultSpec: DefaultString): string { export function getDefaultString(defaultSpec: CT.DefaultString): string {
if (typeof defaultSpec === 'string') { if (typeof defaultSpec === 'string') {
return defaultSpec return defaultSpec
} else { } else {

View File

@@ -1,9 +1,9 @@
import { Config } from "@start9labs/start-sdk/cjs/sdk/lib/config/builder/config"; import { CB } from '@start9labs/start-sdk'
export async function configBuilderToSpec( export async function configBuilderToSpec(
builder: builder:
| Config<Record<string, unknown>, unknown> | CB.Config<Record<string, unknown>, unknown>
| Config<Record<string, unknown>, never>, | CB.Config<Record<string, unknown>, never>,
) { ) {
return builder.build({} as any) return builder.build({} as any)
} }