diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 9c5f6d31a..73e26c53e 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -49,7 +49,7 @@
"patch-db-client": "file: ../../../patch-db/client",
"pbkdf2": "^3.1.2",
"rxjs": "^7.5.6",
- "start-sdk": "^0.4.0-lib0.alpha9",
+ "start-sdk": "^0.4.0-lib0.beta3",
"swiper": "^8.2.4",
"ts-matches": "^5.2.1",
"tslib": "^2.3.0",
@@ -13771,9 +13771,9 @@
}
},
"node_modules/start-sdk": {
- "version": "0.4.0-lib0.alpha9",
- "resolved": "https://registry.npmjs.org/start-sdk/-/start-sdk-0.4.0-lib0.alpha9.tgz",
- "integrity": "sha512-F+ekxjVEKgNv7SU5XCe1rn7PqbKsbqCSS7pecMxcKQmbNlic4iyo3+lIS9JuPBSyTTjJlzJFzkdaxGwf4h83mg==",
+ "version": "0.4.0-lib0.beta3",
+ "resolved": "https://registry.npmjs.org/start-sdk/-/start-sdk-0.4.0-lib0.beta3.tgz",
+ "integrity": "sha512-MuKc4QB6rR2UOVZaT3MApJf5jGtIzUmKGLS4mm6Zqvmud+MP/FQTRB8y7CZjyBmBGXQZcSyFUcEBkR/hQTmLXA==",
"dependencies": {
"@iarna/toml": "^2.2.5",
"lodash": "^4.17.21",
diff --git a/frontend/package.json b/frontend/package.json
index 033fd2b9f..4655d0eac 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -74,7 +74,7 @@
"patch-db-client": "file: ../../../patch-db/client",
"pbkdf2": "^3.1.2",
"rxjs": "^7.5.6",
- "start-sdk": "^0.4.0-lib0.alpha9",
+ "start-sdk": "^0.4.0-lib0.beta3",
"swiper": "^8.2.4",
"ts-matches": "^5.2.1",
"tslib": "^2.3.0",
diff --git a/frontend/projects/ui/src/app/components/backup-drives/backup-drives.component.ts b/frontend/projects/ui/src/app/components/backup-drives/backup-drives.component.ts
index f25957c63..738c29939 100644
--- a/frontend/projects/ui/src/app/components/backup-drives/backup-drives.component.ts
+++ b/frontend/projects/ui/src/app/components/backup-drives/backup-drives.component.ts
@@ -12,7 +12,7 @@ import {
ModalController,
} from '@ionic/angular'
import { GenericFormPage } from 'src/app/modals/generic-form/generic-form.page'
-import { InputSpec } from 'start-sdk/types/config-types'
+import { InputSpec } from 'start-sdk/lib/config/config-types'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { ErrorToastService } from '@start9labs/shared'
import { MappedBackupTarget } from 'src/app/types/mapped-backup-target'
@@ -282,7 +282,7 @@ const CifsSpec: InputSpec = {
'The hostname of your target device on the Local Area Network.',
placeholder: `e.g. 'My Computer' OR 'my-computer.local'`,
pattern: '^[a-zA-Z0-9._-]+( [a-zA-Z0-9]+)*$',
- 'pattern-description': `Must be a valid hostname. e.g. 'My Computer' OR 'my-computer.local'`,
+ patternDescription: `Must be a valid hostname. e.g. 'My Computer' OR 'my-computer.local'`,
nullable: false,
masked: false,
default: null,
@@ -295,7 +295,7 @@ const CifsSpec: InputSpec = {
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',
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
nullable: false,
masked: false,
default: null,
@@ -308,7 +308,7 @@ const CifsSpec: InputSpec = {
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.`,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
nullable: false,
masked: false,
default: null,
@@ -321,7 +321,7 @@ const CifsSpec: InputSpec = {
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.`,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
nullable: true,
masked: true,
default: null,
diff --git a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.ts b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.ts
index 83c550b44..b95fbc7a8 100644
--- a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.ts
+++ b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.ts
@@ -1,6 +1,6 @@
import { Component, Input } from '@angular/core'
import { AbstractControl } from '@angular/forms'
-import { ValueSpecOf } from 'start-sdk/types/config-types'
+import { ValueSpecOf } from 'start-sdk/lib/config/config-types'
@Component({
selector: 'form-file',
diff --git a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.html b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.html
index b4a14447c..639d425bd 100644
--- a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.html
+++ b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.html
@@ -57,6 +57,6 @@
- {{ errors | getError : $any(spec)['pattern-description'] }}
+ {{ errors | getError : $any(spec).patternDescription }}
diff --git a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.ts b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.ts
index c79cbada2..551608bbb 100644
--- a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.ts
+++ b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.ts
@@ -1,6 +1,6 @@
import { Component, Input, inject, Output, EventEmitter } from '@angular/core'
import { FormControl } from '@angular/forms'
-import { ValueSpecOf } from 'start-sdk/types/config-types'
+import { ValueSpecOf } from 'start-sdk/lib/config/config-types'
import { THEME } from '@start9labs/shared'
@Component({
diff --git a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-select/form-select.component.html b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-select/form-select.component.html
index 8beb43015..d9fe4cb0d 100644
--- a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-select/form-select.component.html
+++ b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-select/form-select.component.html
@@ -31,11 +31,14 @@
[selectedText]="
spec.type === 'multiselect' && control.value?.length > 1
? '[' + control.value.length + ' selected]'
- : spec['value-names'][control.value]
+ : spec.values[control.value]
"
>
-
- {{ spec['value-names'][option] }}
+
+ {{ option.value }}
diff --git a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-select/form-select.component.ts b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-select/form-select.component.ts
index ec49cf9bc..7688b0a9d 100644
--- a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-select/form-select.component.ts
+++ b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-select/form-select.component.ts
@@ -1,6 +1,6 @@
import { Component, Input } from '@angular/core'
import { FormControl } from '@angular/forms'
-import { ValueSpecOf } from 'start-sdk/types/config-types'
+import { ValueSpecOf } from 'start-sdk/lib/config/config-types'
@Component({
selector: 'form-select',
diff --git a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-subform/form-subform.component.ts b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-subform/form-subform.component.ts
index 04b44a353..1508a1654 100644
--- a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-subform/form-subform.component.ts
+++ b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-subform/form-subform.component.ts
@@ -1,6 +1,6 @@
import { Component, Input, Output, EventEmitter } from '@angular/core'
import { AbstractControl } from '@angular/forms'
-import { ValueSpecOf } from 'start-sdk/types/config-types'
+import { ValueSpecOf } from 'start-sdk/lib/config/config-types'
@Component({
selector: 'form-subform',
diff --git a/frontend/projects/ui/src/app/components/form-object/form-object/form-object.component.html b/frontend/projects/ui/src/app/components/form-object/form-object/form-object.component.html
index a9f77fcbe..0ba9b727a 100644
--- a/frontend/projects/ui/src/app/components/form-object/form-object/form-object.component.html
+++ b/frontend/projects/ui/src/app/components/form-object/form-object/form-object.component.html
@@ -90,11 +90,9 @@
let i = index
"
>
-
-
-
+
+
+
-
- {{ errors | getError : $any(spec)['pattern-description'] }}
+ {{ errors | getError : $any(spec).patternDescription }}
diff --git a/frontend/projects/ui/src/app/components/form-object/form-object/form-object.component.ts b/frontend/projects/ui/src/app/components/form-object/form-object/form-object.component.ts
index abba90aa8..f12f08fc1 100644
--- a/frontend/projects/ui/src/app/components/form-object/form-object/form-object.component.ts
+++ b/frontend/projects/ui/src/app/components/form-object/form-object/form-object.component.ts
@@ -8,7 +8,7 @@ import {
SimpleChanges,
} from '@angular/core'
import { UntypedFormArray, UntypedFormGroup } from '@angular/forms'
-import { AlertButton, AlertController, ModalController } from '@ionic/angular'
+import { AlertButton, AlertController } from '@ionic/angular'
import {
InputSpec,
ListValueSpecOf,
@@ -16,7 +16,7 @@ import {
ValueSpecBoolean,
ValueSpecList,
ValueSpecUnion,
-} from 'start-sdk/types/config-types'
+} from 'start-sdk/lib/config/config-types'
import { FormService } from 'src/app/services/form.service'
import { THEME, pauseFor } from '@start9labs/shared'
import { v4 } from 'uuid'
@@ -49,7 +49,6 @@ export class FormObjectComponent {
constructor(
private readonly alertCtrl: AlertController,
- private readonly modalCtrl: ModalController,
private readonly formService: FormService,
@Inject(DOCUMENT) private readonly document: Document,
) {}
@@ -86,9 +85,7 @@ export class FormObjectComponent {
if (spec.type === 'list' && ['object', 'union'].includes(spec.subtype)) {
this.objectListDisplay[key] = []
this.formGroup.get(key)?.value.forEach((obj: any, index: number) => {
- const displayAs = (spec.spec as ListValueSpecOf<'object'>)[
- 'display-as'
- ]
+ const displayAs = (spec.spec as ListValueSpecOf<'object'>).displayAs
this.objectListDisplay[key][index] = {
expanded: false,
displayAs: displayAs
@@ -213,9 +210,7 @@ export class FormObjectComponent {
arr.insert(index, newItem)
if (['object', 'union'].includes(listSpec.subtype)) {
- const displayAs = (listSpec.spec as ListValueSpecOf<'object'>)[
- 'display-as'
- ]
+ const displayAs = (listSpec.spec as ListValueSpecOf<'object'>).displayAs
this.objectListDisplay[key].push({
expanded: false,
displayAs: displayAs ? Mustache.render(displayAs, newItem.value) : '',
diff --git a/frontend/projects/ui/src/app/components/form-object/form-union/form-union.component.html b/frontend/projects/ui/src/app/components/form-object/form-union/form-union.component.html
index 861e184c6..e6cad5650 100644
--- a/frontend/projects/ui/src/app/components/form-object/form-union/form-union.component.html
+++ b/frontend/projects/ui/src/app/components/form-object/form-union/form-union.component.html
@@ -3,8 +3,8 @@
@@ -26,7 +26,7 @@
*ngFor="let option of spec.variants | keyvalue"
[value]="option.key"
>
- {{ spec.tag['variant-names'][option.key] }}
+ {{ spec.variants[option.key].name }}
diff --git a/frontend/projects/ui/src/app/components/form-object/form-union/form-union.component.ts b/frontend/projects/ui/src/app/components/form-object/form-union/form-union.component.ts
index 6994e92c5..064be5660 100644
--- a/frontend/projects/ui/src/app/components/form-object/form-union/form-union.component.ts
+++ b/frontend/projects/ui/src/app/components/form-object/form-union/form-union.component.ts
@@ -2,7 +2,11 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
import { UntypedFormGroup } from '@angular/forms'
import { v4 } from 'uuid'
import { FormService } from 'src/app/services/form.service'
-import { ValueSpecUnion, InputSpec } from 'start-sdk/types/config-types'
+import {
+ ValueSpecUnion,
+ InputSpec,
+ unionSelectKey,
+} from 'start-sdk/lib/config/config-types'
@Component({
selector: 'form-union',
@@ -11,21 +15,23 @@ import { ValueSpecUnion, InputSpec } from 'start-sdk/types/config-types'
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FormUnionComponent {
+ readonly unionSelectKey = unionSelectKey
+
@Input() formGroup!: UntypedFormGroup
@Input() spec!: ValueSpecUnion
@Input() current?: Record
@Input() original?: Record
get selectedVariant(): string {
- return this.formGroup.get(this.spec.tag.id)?.value
+ return this.formGroup.get(unionSelectKey)?.value
}
get variantName(): string {
- return this.spec.tag['variant-names'][this.selectedVariant]
+ return this.spec.variants[this.selectedVariant].name
}
get variantSpec(): InputSpec {
- return this.spec.variants[this.selectedVariant]
+ return this.spec.variants[this.selectedVariant].spec
}
get hasNewOptions(): boolean {
@@ -38,10 +44,8 @@ export class FormUnionComponent {
constructor(private readonly formService: FormService) {}
updateUnion(e: any): void {
- const tagId = this.spec.tag.id
-
Object.keys(this.formGroup.controls).forEach(control => {
- if (control === tagId) return
+ if (control === unionSelectKey) return
this.formGroup.removeControl(control)
})
@@ -51,7 +55,7 @@ export class FormUnionComponent {
)
Object.keys(unionGroup.controls).forEach(control => {
- if (control === tagId) return
+ if (control === unionSelectKey) return
this.formGroup.addControl(control, unionGroup.controls[control])
})
}
diff --git a/frontend/projects/ui/src/app/components/form-object/form-warning.directive.ts b/frontend/projects/ui/src/app/components/form-object/form-warning.directive.ts
index d568062f3..ab87fa01f 100644
--- a/frontend/projects/ui/src/app/components/form-object/form-warning.directive.ts
+++ b/frontend/projects/ui/src/app/components/form-object/form-warning.directive.ts
@@ -1,5 +1,5 @@
import { Directive } from '@angular/core'
-import { ValueSpec, ValueSpecUnion } from 'start-sdk/types/config-types'
+import { ValueSpec, ValueSpecUnion } from 'start-sdk/lib/config/config-types'
import { AlertButton, AlertController } from '@ionic/angular'
@Directive({
diff --git a/frontend/projects/ui/src/app/modals/app-config/app-config.page.ts b/frontend/projects/ui/src/app/modals/app-config/app-config.page.ts
index 0fae102f8..867efceb6 100644
--- a/frontend/projects/ui/src/app/modals/app-config/app-config.page.ts
+++ b/frontend/projects/ui/src/app/modals/app-config/app-config.page.ts
@@ -13,7 +13,7 @@ import {
isObject,
} from '@start9labs/shared'
import { DependentInfo } from 'src/app/types/dependent-info'
-import { InputSpec } from 'start-sdk/types/config-types'
+import { InputSpec } from 'start-sdk/lib/config/config-types'
import {
DataModel,
PackageDataEntry,
diff --git a/frontend/projects/ui/src/app/modals/generic-form/generic-form.page.ts b/frontend/projects/ui/src/app/modals/generic-form/generic-form.page.ts
index 6039ab721..4893f7da1 100644
--- a/frontend/projects/ui/src/app/modals/generic-form/generic-form.page.ts
+++ b/frontend/projects/ui/src/app/modals/generic-form/generic-form.page.ts
@@ -5,7 +5,7 @@ import {
convertValuesRecursive,
FormService,
} from 'src/app/services/form.service'
-import { InputSpec } from 'start-sdk/types/config-types'
+import { InputSpec } from 'start-sdk/lib/config/config-types'
export interface ActionButton {
text: string
diff --git a/frontend/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.page.ts b/frontend/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.page.ts
index b9ee3819c..58f53c662 100644
--- a/frontend/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.page.ts
+++ b/frontend/projects/ui/src/app/modals/marketplace-settings/marketplace-settings.page.ts
@@ -14,7 +14,7 @@ import { ActionSheetButton } from '@ionic/core'
import { ErrorToastService, sameUrl, toUrl } from '@start9labs/shared'
import { AbstractMarketplaceService } from '@start9labs/marketplace'
import { ApiService } from 'src/app/services/api/embassy-api.service'
-import { ValueSpecObject } from 'start-sdk/types/config-types'
+import { ValueSpecObject } from 'start-sdk/lib/config/config-types'
import {
GenericFormPage,
GenericFormOptions,
@@ -276,7 +276,7 @@ function getMarketplaceValueSpec(): ValueSpecObject {
nullable: false,
masked: false,
pattern: `https?:\/\/[a-zA-Z0-9][a-zA-Z0-9-\.]+[a-zA-Z0-9]\.[^\s]{2,}`,
- 'pattern-description': 'Must be a valid URL',
+ patternDescription: 'Must be a valid URL',
placeholder: 'e.g. https://example.org',
default: null,
textarea: false,
diff --git a/frontend/projects/ui/src/app/pages/developer-routes/developer-list/developer-list.page.ts b/frontend/projects/ui/src/app/pages/developer-routes/developer-list/developer-list.page.ts
index 1113410f2..b006e6caa 100644
--- a/frontend/projects/ui/src/app/pages/developer-routes/developer-list/developer-list.page.ts
+++ b/frontend/projects/ui/src/app/pages/developer-routes/developer-list/developer-list.page.ts
@@ -12,7 +12,7 @@ import {
} from 'src/app/modals/generic-input/generic-input.component'
import { PatchDB } from 'patch-db-client'
import { ApiService } from 'src/app/services/api/embassy-api.service'
-import { InputSpec } from 'start-sdk/types/config-types'
+import { InputSpec } from 'start-sdk/lib/config/config-types'
import * as yaml from 'js-yaml'
import { v4 } from 'uuid'
import { DataModel, DevData } from 'src/app/services/patch-db/data-model'
@@ -227,7 +227,7 @@ const SAMPLE_CONFIG: InputSpec = {
description: 'Example description for required string input.',
placeholder: 'Enter string value',
pattern: '^[a-zA-Z0-9! _]+$',
- 'pattern-description': 'Must be alphanumeric (may contain underscore).',
+ patternDescription: 'Must be alphanumeric (may contain underscore).',
default: null,
textarea: false,
warning: null,
@@ -256,8 +256,7 @@ const SAMPLE_CONFIG: InputSpec = {
'sample-select': {
type: 'multiselect',
name: 'Example Enum Select',
- values: ['red', 'blue', 'green'],
- 'value-names': {
+ values: {
red: 'Red',
blue: 'Blue',
green: 'Green',
diff --git a/frontend/projects/ui/src/app/pages/developer-routes/developer-menu/form-info.ts b/frontend/projects/ui/src/app/pages/developer-routes/developer-menu/form-info.ts
index 97bc54804..56b318f0a 100644
--- a/frontend/projects/ui/src/app/pages/developer-routes/developer-menu/form-info.ts
+++ b/frontend/projects/ui/src/app/pages/developer-routes/developer-menu/form-info.ts
@@ -1,4 +1,4 @@
-import { InputSpec } from 'start-sdk/types/config-types'
+import { InputSpec } from 'start-sdk/lib/config/config-types'
import { DevProjectData } from 'src/app/services/patch-db/data-model'
export type BasicInfo = {
@@ -28,7 +28,7 @@ export function getBasicInfoSpec(devData: DevProjectData): InputSpec {
nullable: false,
masked: false,
pattern: '^([a-z][a-z0-9]*)(-[a-z0-9]+)*$',
- 'pattern-description': 'Must be kebab case',
+ patternDescription: 'Must be kebab case',
default: basicInfo?.id || '',
textarea: false,
warning: null,
@@ -41,7 +41,7 @@ export function getBasicInfoSpec(devData: DevProjectData): InputSpec {
nullable: false,
masked: false,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
default: basicInfo ? basicInfo.title : devData.name,
textarea: false,
warning: null,
@@ -55,7 +55,7 @@ export function getBasicInfoSpec(devData: DevProjectData): InputSpec {
nullable: false,
masked: false,
pattern: '^([0-9]+).([0-9]+).([0-9]+).([0-9]+)$',
- 'pattern-description': 'Must be valid Emver version',
+ patternDescription: 'Must be valid Emver version',
default: basicInfo?.['service-version-number'] || '',
textarea: false,
warning: null,
@@ -77,7 +77,7 @@ export function getBasicInfoSpec(devData: DevProjectData): InputSpec {
textarea: true,
default: basicInfo?.description?.short || '',
pattern: '^.{1,320}$',
- 'pattern-description': 'Must be shorter than 320 characters',
+ patternDescription: 'Must be shorter than 320 characters',
warning: null,
},
long: {
@@ -90,7 +90,7 @@ export function getBasicInfoSpec(devData: DevProjectData): InputSpec {
textarea: true,
default: basicInfo?.description?.long || '',
pattern: '^.{1,5000}$',
- 'pattern-description': 'Must be shorter than 5000 characters',
+ patternDescription: 'Must be shorter than 5000 characters',
warning: null,
},
},
@@ -104,7 +104,7 @@ export function getBasicInfoSpec(devData: DevProjectData): InputSpec {
nullable: false,
masked: false,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: true,
default: basicInfo?.['release-notes'] || '',
warning: null,
@@ -113,18 +113,7 @@ export function getBasicInfoSpec(devData: DevProjectData): InputSpec {
type: 'select',
name: 'License',
warning: null,
- values: [
- 'gnu-agpl-v3',
- 'gnu-gpl-v3',
- 'gnu-lgpl-v3',
- 'mozilla-public-license-2.0',
- 'apache-license-2.0',
- 'mit',
- 'boost-software-license-1.0',
- 'the-unlicense',
- 'custom',
- ],
- 'value-names': {
+ values: {
'gnu-agpl-v3': 'GNU AGPLv3',
'gnu-gpl-v3': 'GNU GPLv3',
'gnu-lgpl-v3': 'GNU LGPLv3',
@@ -136,6 +125,7 @@ export function getBasicInfoSpec(devData: DevProjectData): InputSpec {
custom: 'Custom',
},
description: 'Example description for select',
+ nullable: false,
default: 'mit',
},
'wrapper-repo': {
@@ -145,7 +135,7 @@ export function getBasicInfoSpec(devData: DevProjectData): InputSpec {
'The Start9 wrapper repository URL for the package. This repo contains the manifest file (this), any scripts necessary for configuration, backups, actions, or health checks',
placeholder: 'e.g. www.github.com/example',
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
nullable: false,
masked: false,
default: basicInfo?.['wrapper-repo'] || '',
@@ -158,7 +148,7 @@ export function getBasicInfoSpec(devData: DevProjectData): InputSpec {
description: 'The original project repository URL',
placeholder: 'e.g. www.github.com/example',
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
nullable: true,
masked: false,
default: basicInfo?.['upstream-repo'] || '',
@@ -171,7 +161,7 @@ export function getBasicInfoSpec(devData: DevProjectData): InputSpec {
description: 'URL to the support site / channel for the project',
placeholder: 'e.g. start9.com/support',
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
nullable: true,
masked: false,
default: basicInfo?.['support-site'] || '',
@@ -184,7 +174,7 @@ export function getBasicInfoSpec(devData: DevProjectData): InputSpec {
description: 'URL to the marketing site / channel for the project',
placeholder: 'e.g. start9.com',
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
nullable: true,
masked: false,
default: basicInfo?.['marketing-site'] || '',
diff --git a/frontend/projects/ui/src/app/pages/server-routes/wifi/wifi.page.ts b/frontend/projects/ui/src/app/pages/server-routes/wifi/wifi.page.ts
index b6e1b966f..afe928b43 100644
--- a/frontend/projects/ui/src/app/pages/server-routes/wifi/wifi.page.ts
+++ b/frontend/projects/ui/src/app/pages/server-routes/wifi/wifi.page.ts
@@ -9,7 +9,7 @@ import {
import { AlertInput } from '@ionic/core'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { ActionSheetButton } from '@ionic/core'
-import { ValueSpecObject } from 'start-sdk/types/config-types'
+import { ValueSpecObject } from 'start-sdk/lib/config/config-types'
import { RR } from 'src/app/services/api/api.types'
import { pauseFor, ErrorToastService } from '@start9labs/shared'
import {
@@ -361,7 +361,7 @@ function getWifiValueSpec(
description: null,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
nullable: false,
masked: false,
default: ssid || null,
@@ -376,7 +376,7 @@ function getWifiValueSpec(
nullable: !needsPW,
masked: true,
pattern: '^.{8,}$',
- 'pattern-description': 'Must be longer than 8 characters',
+ patternDescription: 'Must be longer than 8 characters',
default: null,
textarea: false,
warning: null,
diff --git a/frontend/projects/ui/src/app/services/api/api.fixures.ts b/frontend/projects/ui/src/app/services/api/api.fixures.ts
index 016ae95b9..b923f18bb 100644
--- a/frontend/projects/ui/src/app/services/api/api.fixures.ts
+++ b/frontend/projects/ui/src/app/services/api/api.fixures.ts
@@ -714,46 +714,43 @@ export module Mock {
spec: {
'bitcoind-p2p': {
type: 'union',
- tag: {
- id: 'type',
- name: 'Bitcoin Core P2P',
- description:
- 'The Bitcoin Core node to connect to over the peer-to-peer (P2P) interface:
- Bitcoin Core: The Bitcoin Core service installed on this device
- External Node: A Bitcoin node running on a different device
',
- 'variant-names': {
- internal: 'Bitcoin Core',
- external: 'External Node',
- },
- warning: null,
- },
+ name: 'Bitcoin Core P2P',
+ description:
+ 'The Bitcoin Core node to connect to over the peer-to-peer (P2P) interface:
- Bitcoin Core: The Bitcoin Core service installed on this device
- External Node: A Bitcoin node running on a different device
',
+ warning: null,
default: 'internal',
+ nullable: false,
variants: {
- internal: {},
+ internal: { name: 'Internal', spec: {} },
external: {
- 'p2p-host': {
- type: 'string',
- name: 'Public Address',
- description: 'The public address of your Bitcoin Core server',
- nullable: false,
- masked: false,
- placeholder: null,
- pattern: null,
- 'pattern-description': null,
- textarea: false,
- warning: null,
- default: null,
- },
- 'p2p-port': {
- type: 'number',
- name: 'P2P Port',
- description:
- 'The port that your Bitcoin Core P2P server is bound to',
- nullable: false,
- range: '[0,65535]',
- integral: true,
- default: 8333,
- placeholder: null,
- warning: null,
- units: null,
+ name: 'External',
+ spec: {
+ 'p2p-host': {
+ type: 'string',
+ name: 'Public Address',
+ description: 'The public address of your Bitcoin Core server',
+ nullable: false,
+ masked: false,
+ placeholder: null,
+ pattern: null,
+ patternDescription: null,
+ textarea: false,
+ warning: null,
+ default: null,
+ },
+ 'p2p-port': {
+ type: 'number',
+ name: 'P2P Port',
+ description:
+ 'The port that your Bitcoin Core P2P server is bound to',
+ nullable: false,
+ range: '[0,65535]',
+ integral: true,
+ default: 8333,
+ placeholder: null,
+ warning: null,
+ units: null,
+ },
},
},
},
@@ -782,7 +779,7 @@ export module Mock {
nullable: false,
default: 'defaultrpcusername',
pattern: '^[a-zA-Z]+$',
- 'pattern-description': 'must contain only letters.',
+ patternDescription: 'must contain only letters.',
masked: false,
textarea: false,
},
@@ -795,7 +792,7 @@ export module Mock {
nullable: false,
default: 'defaultrpcusername',
pattern: '^[a-zA-Z]+$',
- 'pattern-description': 'must contain only letters.',
+ patternDescription: 'must contain only letters.',
masked: false,
textarea: false,
},
@@ -812,7 +809,7 @@ export module Mock {
},
masked: true,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
},
rpcpass2: {
@@ -828,7 +825,7 @@ export module Mock {
},
masked: true,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
},
},
@@ -847,7 +844,6 @@ export module Mock {
name: 'Needed File',
type: 'file',
description: 'A file we need',
- placeholder: null, // @TODO delete
warning: 'Testing warning',
nullable: false,
extensions: ['.png'],
@@ -873,10 +869,9 @@ export module Mock {
],
// the outer spec here, at the list level, says that what's inside (the inner spec) pertains to its inner elements.
// it just so happens that ValueSpecObject's have the field { spec: InputSpec }
- // see 'union-list' below for a different example.
spec: {
- 'unique-by': 'last-name',
- 'display-as': `I'm {{last-name}}, {{first-name}} {{last-name}}`,
+ uniqueBy: 'last-name',
+ displayAs: `I'm {{last-name}}, {{first-name}} {{last-name}}`,
spec: {
'first-name': {
name: 'First Name',
@@ -886,7 +881,7 @@ export module Mock {
masked: false,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
warning: null,
default: null,
@@ -901,7 +896,7 @@ export module Mock {
len: 12,
},
pattern: '^[a-zA-Z]+$',
- 'pattern-description': 'must contain only letters.',
+ patternDescription: 'must contain only letters.',
masked: false,
placeholder: null,
textarea: false,
@@ -922,77 +917,10 @@ export module Mock {
},
},
},
- 'union-list': {
- name: 'Union List',
- type: 'list',
- subtype: 'union',
- description: 'This is a sample list of unions',
- warning: 'If you change this, things may work.',
- // a list of union selections. e.g. 'summer', 'winter',...
- default: ['summer'],
- range: '[0, 2]',
- spec: {
- tag: {
- id: 'preference',
- description: null,
- warning: null,
- 'variant-names': {
- summer: 'Summer',
- winter: 'Winter',
- other: 'Other',
- },
- name: 'Preference',
- },
- 'display-as': null,
- // this default is used to make a union selection when a new list element is first created
- default: 'summer',
- variants: {
- summer: {
- 'favorite-tree': {
- name: 'Favorite Tree',
- type: 'string',
- nullable: false,
- description: 'What is your favorite tree?',
- default: 'Maple',
- masked: false,
- placeholder: null,
- pattern: null,
- 'pattern-description': null,
- textarea: false,
- warning: null,
- },
- 'favorite-flower': {
- name: 'Favorite Flower',
- type: 'select',
- description: 'Select your favorite flower',
- warning: null,
- 'value-names': {
- none: 'Hate Flowers',
- red: 'Red',
- blue: 'Blue',
- purple: 'Purple',
- },
- values: ['none', 'red', 'blue', 'purple'],
- default: 'none',
- },
- },
- winter: {
- 'like-snow': {
- name: 'Like Snow?',
- type: 'boolean',
- description: 'Do you like snow or not?',
- warning: null,
- default: true,
- },
- },
- },
- 'unique-by': 'preference',
- },
- },
'random-select': {
name: 'Random Select',
type: 'select',
- 'value-names': {
+ values: {
hello: 'Hello',
goodbye: 'Goodbye',
sup: 'Sup',
@@ -1000,7 +928,7 @@ export module Mock {
default: 'sup',
description: 'This is not even real.',
warning: 'Be careful changing this!',
- values: ['hello', 'goodbye', 'sup'],
+ nullable: false,
},
notifications: {
name: 'Notification Preferences',
@@ -1008,14 +936,13 @@ export module Mock {
description: 'how you want to be notified',
warning: null,
range: '(1,3]',
- 'value-names': {
+ values: {
email: 'EEEEmail',
text: 'Texxxt',
call: 'Ccccall',
push: 'PuuuusH',
webhook: 'WebHooookkeee',
},
- values: ['email', 'text', 'call', 'push', 'webhook'],
default: ['email'],
},
'favorite-number': {
@@ -1066,7 +993,7 @@ export module Mock {
masked: false,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
warning: null,
default: null,
@@ -1079,7 +1006,7 @@ export module Mock {
masked: false,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
warning: null,
default: null,
@@ -1095,8 +1022,8 @@ export module Mock {
range: '[0,2]',
default: [],
spec: {
- 'unique-by': null,
- 'display-as': null,
+ uniqueBy: null,
+ displayAs: null,
spec: {
rulemakername: {
name: 'Rulemaker Name',
@@ -1110,7 +1037,7 @@ export module Mock {
masked: false,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
warning: null,
},
@@ -1122,7 +1049,7 @@ export module Mock {
default: '192.168.1.0',
pattern:
'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$',
- 'pattern-description': 'may only contain numbers and periods',
+ patternDescription: 'may only contain numbers and periods',
masked: false,
placeholder: null,
textarea: false,
@@ -1138,7 +1065,7 @@ export module Mock {
nullable: false,
default: 'defaultrpcusername',
pattern: '^[a-zA-Z]+$',
- 'pattern-description': 'must contain only letters.',
+ patternDescription: 'must contain only letters.',
masked: false,
placeholder: null,
textarea: false,
@@ -1156,7 +1083,7 @@ export module Mock {
masked: true,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
warning: null,
},
@@ -1165,78 +1092,75 @@ export module Mock {
'bitcoin-node': {
type: 'union',
default: 'internal',
- tag: {
- id: 'type',
- 'variant-names': {
- internal: 'Internal',
- external: 'External',
- },
- name: 'Bitcoin Node Settings',
- description: 'Options',
- warning: 'Careful changing this',
- },
+ name: 'Bitcoin Node Settings',
+ description: 'Options',
+ warning: 'Careful changing this',
+ nullable: false,
variants: {
- internal: {},
+ internal: { name: 'Internal', spec: {} },
external: {
- 'emergency-contact': {
- name: 'Emergency Contact',
- type: 'object',
- description: 'The person to contact in case of emergency.',
- warning: null,
- spec: {
- name: {
- type: 'string',
- name: 'Name',
- description: null,
- nullable: false,
- masked: false,
- pattern: '^[a-zA-Z]+$',
- 'pattern-description': 'Must contain only letters.',
- placeholder: null,
- textarea: false,
- warning: null,
- default: null,
- },
- email: {
- type: 'string',
- name: 'Email',
- description: null,
- nullable: false,
- masked: false,
- placeholder: null,
- pattern: null,
- 'pattern-description': null,
- textarea: false,
- warning: null,
- default: null,
+ name: 'External',
+ spec: {
+ 'emergency-contact': {
+ name: 'Emergency Contact',
+ type: 'object',
+ description: 'The person to contact in case of emergency.',
+ warning: null,
+ spec: {
+ name: {
+ type: 'string',
+ name: 'Name',
+ description: null,
+ nullable: false,
+ masked: false,
+ pattern: '^[a-zA-Z]+$',
+ patternDescription: 'Must contain only letters.',
+ placeholder: null,
+ textarea: false,
+ warning: null,
+ default: null,
+ },
+ email: {
+ type: 'string',
+ name: 'Email',
+ description: null,
+ nullable: false,
+ masked: false,
+ placeholder: null,
+ pattern: null,
+ patternDescription: null,
+ textarea: false,
+ warning: null,
+ default: null,
+ },
},
},
- },
- 'public-domain': {
- name: 'Public Domain',
- type: 'string',
- description: 'the public address of the node',
- nullable: false,
- default: 'bitcoinnode.com',
- pattern: '.*',
- 'pattern-description': 'anything',
- masked: false,
- placeholder: null,
- textarea: false,
- warning: null,
- },
- 'private-domain': {
- name: 'Private Domain',
- type: 'string',
- description: 'the private address of the node',
- nullable: false,
- masked: true,
- placeholder: null,
- pattern: null,
- 'pattern-description': null,
- textarea: false,
- warning: null,
- default: null,
+ 'public-domain': {
+ name: 'Public Domain',
+ type: 'string',
+ description: 'the public address of the node',
+ nullable: false,
+ default: 'bitcoinnode.com',
+ pattern: '.*',
+ patternDescription: 'anything',
+ masked: false,
+ placeholder: null,
+ textarea: false,
+ warning: null,
+ },
+ 'private-domain': {
+ name: 'Private Domain',
+ type: 'string',
+ description: 'the private address of the node',
+ nullable: false,
+ masked: true,
+ placeholder: null,
+ pattern: null,
+ patternDescription: null,
+ textarea: false,
+ warning: null,
+ default: null,
+ },
},
},
},
@@ -1263,7 +1187,7 @@ export module Mock {
masked: true,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
warning: null,
default: null,
@@ -1283,7 +1207,7 @@ export module Mock {
placeholder: null,
pattern:
'((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|((^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$)|(^[a-z2-7]{16}\\.onion$)|(^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$))',
- 'pattern-description': 'must be a valid ipv4, ipv6, or domain name',
+ patternDescription: 'must be a valid ipv4, ipv6, or domain name',
},
},
rpcauth: {
@@ -1298,7 +1222,7 @@ export module Mock {
masked: false,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
},
},
'more-advanced': {
@@ -1328,7 +1252,7 @@ export module Mock {
masked: false,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
warning: null,
default: null,
@@ -1341,7 +1265,7 @@ export module Mock {
masked: false,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
warning: null,
default: null,
@@ -1354,7 +1278,7 @@ export module Mock {
masked: false,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
warning: null,
default: null,
@@ -1368,8 +1292,8 @@ export module Mock {
range: '[0,2]',
default: [],
spec: {
- 'unique-by': null,
- 'display-as': null,
+ uniqueBy: null,
+ displayAs: null,
spec: {
lawname: {
name: 'Law Name',
@@ -1383,7 +1307,7 @@ export module Mock {
masked: false,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
warning: null,
},
@@ -1395,7 +1319,7 @@ export module Mock {
default: '192.168.1.0',
pattern:
'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$',
- 'pattern-description':
+ patternDescription:
'may only contain numbers and periods',
masked: false,
placeholder: null,
@@ -1413,7 +1337,7 @@ export module Mock {
masked: false,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
warning: null,
default: null,
@@ -1429,8 +1353,8 @@ export module Mock {
range: '[0,2]',
default: [],
spec: {
- 'unique-by': null,
- 'display-as': null,
+ uniqueBy: null,
+ displayAs: null,
spec: {
rulemakername: {
name: 'Rulemaker Name',
@@ -1444,7 +1368,7 @@ export module Mock {
masked: false,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
warning: null,
},
@@ -1456,8 +1380,7 @@ export module Mock {
default: '192.168.1.0',
pattern:
'^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$',
- 'pattern-description':
- 'may only contain numbers and periods',
+ patternDescription: 'may only contain numbers and periods',
masked: false,
placeholder: null,
textarea: false,
@@ -1473,7 +1396,7 @@ export module Mock {
nullable: false,
default: 'defaultrpcusername',
pattern: '^[a-zA-Z]+$',
- 'pattern-description': 'must contain only letters.',
+ patternDescription: 'must contain only letters.',
masked: false,
placeholder: null,
textarea: false,
@@ -1491,7 +1414,7 @@ export module Mock {
masked: true,
placeholder: null,
pattern: null,
- 'pattern-description': null,
+ patternDescription: null,
textarea: false,
warning: null,
},
@@ -1520,7 +1443,6 @@ export module Mock {
age: 60,
},
],
- 'union-list': undefined,
'random-select': ['goodbye'],
'favorite-number': 0,
rpcsettings: {
@@ -1601,7 +1523,7 @@ export module Mock {
nullable: false,
masked: false,
pattern: '^[a-zA-Z]+$',
- 'pattern-description': 'Must contain only letters.',
+ patternDescription: 'Must contain only letters.',
textarea: false,
warning: null,
default: null,
diff --git a/frontend/projects/ui/src/app/services/api/api.types.ts b/frontend/projects/ui/src/app/services/api/api.types.ts
index b2b519b3a..d1cd719c8 100644
--- a/frontend/projects/ui/src/app/services/api/api.types.ts
+++ b/frontend/projects/ui/src/app/services/api/api.types.ts
@@ -1,7 +1,7 @@
import { Dump, Revision } from 'patch-db-client'
import { MarketplacePkg, StoreInfo, Manifest } from '@start9labs/marketplace'
import { PackagePropertiesVersioned } from 'src/app/util/properties.util'
-import { InputSpec } from 'start-sdk/types/config-types'
+import { InputSpec } from 'start-sdk/lib/config/config-types'
import {
DataModel,
DependencyError,
diff --git a/frontend/projects/ui/src/app/services/form.service.ts b/frontend/projects/ui/src/app/services/form.service.ts
index 6b4b8b39b..46447a580 100644
--- a/frontend/projects/ui/src/app/services/form.service.ts
+++ b/frontend/projects/ui/src/app/services/form.service.ts
@@ -14,7 +14,6 @@ import {
ListValueSpecObject,
ListValueSpecOf,
ListValueSpecString,
- ListValueSpecUnion,
UniqueBy,
ValueSpec,
ValueSpecSelect,
@@ -25,7 +24,8 @@ import {
ValueSpecObject,
ValueSpecString,
ValueSpecUnion,
-} from 'start-sdk/types/config-types'
+ unionSelectKey,
+} from 'start-sdk/lib/config/config-types'
import { getDefaultString, Range } from '../util/config-utilities'
const Mustache = require('mustache')
@@ -37,18 +37,16 @@ export class FormService {
createForm(
spec: InputSpec,
- current: { [key: string]: any } = {},
+ current: Record = {},
): UntypedFormGroup {
return this.getFormGroup(spec, [], current)
}
getUnionObject(
- spec: ValueSpecUnion | ListValueSpecUnion,
- selection: string,
- current?: { [key: string]: any } | null,
+ spec: ValueSpecUnion,
+ selection: string | null,
): UntypedFormGroup {
- const { variants, tag } = spec
- const { name, description, warning, 'variant-names': variantNames } = tag
+ const { name, description, warning, variants, nullable } = spec
const enumSpec: ValueSpecSelect = {
type: 'select',
@@ -56,14 +54,22 @@ export class FormService {
description,
warning,
default: selection,
- values: Object.keys(variants),
- 'value-names': variantNames,
+ nullable,
+ values: Object.keys(variants).reduce(
+ (prev, curr) => ({
+ ...prev,
+ [curr]: variants[curr].name,
+ }),
+ {},
+ ),
}
- return this.getFormGroup(
- { [spec.tag.id]: enumSpec, ...spec.variants[selection] },
- [],
- current,
- )
+
+ const selectedSpec = selection ? variants[selection].spec : {}
+
+ return this.getFormGroup({
+ ['selectedVariant']: enumSpec,
+ ...selectedSpec,
+ })
}
getListItem(spec: ValueSpecList, entry: any) {
@@ -74,15 +80,13 @@ export class FormService {
return this.formBuilder.control(entry, listItemValidators)
} else if (isValueSpecListOf(spec, 'object')) {
return this.getFormGroup(spec.spec.spec, listItemValidators, entry)
- } else if (isValueSpecListOf(spec, 'union')) {
- return this.getUnionObject(spec.spec, spec.spec.default, entry)
}
}
private getFormGroup(
config: InputSpec,
validators: ValidatorFn[] = [],
- current?: { [key: string]: any } | null,
+ current?: Record | null,
): UntypedFormGroup {
let group: Record<
string,
@@ -129,13 +133,12 @@ export class FormService {
fileValidators(spec),
)
case 'union':
- const currentSelection = currentValue?.[spec.tag.id]
+ const currentSelection = currentValue?.[unionSelectKey]
const isValid = !!spec.variants[currentSelection]
return this.getUnionObject(
spec,
isValid ? currentSelection : spec.default,
- isValid ? currentValue : undefined,
)
case 'boolean':
case 'select':
@@ -273,23 +276,20 @@ export function listUnique(spec: ValueSpecList): ValidatorFn {
for (let idx = 0; idx < list.length; idx++) {
for (let idx2 = idx + 1; idx2 < list.length; idx2++) {
if (listItemEquals(spec, list[idx], list[idx2])) {
+ const objSpec = spec.spec
let display1: string
let display2: string
- let uniqueMessage = isObjectOrUnion(spec.spec)
- ? uniqueByMessageWrapper(
- spec.spec['unique-by'],
- spec.spec,
- list[idx],
- )
+ let uniqueMessage = isObject(objSpec)
+ ? uniqueByMessageWrapper(objSpec.uniqueBy, objSpec, list[idx])
: ''
- if (isObjectOrUnion(spec.spec) && spec.spec['display-as']) {
+ if (isObject(objSpec) && objSpec.displayAs) {
display1 = `"${(Mustache as any).render(
- spec.spec['display-as'],
+ objSpec.displayAs,
list[idx],
)}"`
display2 = `"${(Mustache as any).render(
- spec.spec['display-as'],
+ objSpec.displayAs,
list[idx2],
)}"`
} else {
@@ -318,11 +318,7 @@ function listItemEquals(spec: ValueSpecList, val1: any, val2: any): boolean {
case 'object':
const obj: ListValueSpecObject = spec.spec as any
- return listObjEquals(obj['unique-by'], obj, val1, val2)
- case 'union':
- const union: ListValueSpecUnion = spec.spec as any
-
- return unionEquals(union['unique-by'], union, val1, val2)
+ return listObjEquals(obj.uniqueBy, obj, val1, val2)
default:
return false
}
@@ -425,19 +421,18 @@ function objEquals(
function unionEquals(
uniqueBy: UniqueBy,
- spec: ValueSpecUnion | ListValueSpecUnion,
+ spec: ValueSpecUnion,
val1: any,
val2: any,
): boolean {
- const tagId = spec.tag.id
- const variant = spec.variants[val1[tagId]]
+ const variantSpec = spec.variants[val1[unionSelectKey]].spec
if (!uniqueBy) {
return false
} else if (typeof uniqueBy === 'string') {
- if (uniqueBy === tagId) {
- return val1[tagId] === val2[tagId]
+ if (uniqueBy === unionSelectKey) {
+ return val1[unionSelectKey] === val2[unionSelectKey]
} else {
- return itemEquals(variant[uniqueBy], val1[uniqueBy], val2[uniqueBy])
+ return itemEquals(variantSpec[uniqueBy], val1[uniqueBy], val2[uniqueBy])
}
} else if ('any' in uniqueBy) {
for (let subSpec of uniqueBy.any) {
@@ -459,19 +454,10 @@ function unionEquals(
function uniqueByMessageWrapper(
uniqueBy: UniqueBy,
- spec: ListValueSpecObject | ListValueSpecUnion,
+ spec: ListValueSpecObject,
obj: Record,
) {
- let configSpec: InputSpec
- if (isUnion(spec)) {
- const tagId = spec.tag.id
- configSpec = {
- [tagId]: { name: spec.tag.name } as ValueSpec,
- ...spec.variants[obj[tagId]],
- }
- } else {
- configSpec = spec.spec
- }
+ let configSpec = spec.spec
const message = uniqueByMessage(uniqueBy, configSpec)
if (message) {
@@ -509,16 +495,9 @@ function uniqueByMessage(
: '(' + ret + ')'
}
-function isObjectOrUnion(
- spec: ListValueSpecOf,
-): spec is ListValueSpecObject | ListValueSpecUnion {
- // only lists of objects and unions have unique-by
- return 'unique-by' in spec
-}
-
-function isUnion(spec: any): spec is ListValueSpecUnion {
- // only unions have tag
- return !!spec.tag
+function isObject(spec: ListValueSpecOf): spec is ListValueSpecObject {
+ // only lists of objects have uniqueBy
+ return 'uniqueBy' in spec
}
export function convertValuesRecursive(
@@ -540,7 +519,8 @@ export function convertValuesRecursive(
convertValuesRecursive(valueSpec.spec, group.get(key) as UntypedFormGroup)
} else if (valueSpec.type === 'union') {
const formGr = group.get(key) as UntypedFormGroup
- const spec = valueSpec.variants[formGr.controls[valueSpec.tag.id].value]
+ const spec =
+ valueSpec.variants[formGr.controls[unionSelectKey].value].spec
convertValuesRecursive(spec, formGr)
} else if (valueSpec.type === 'list') {
const formArr = group.get(key) as UntypedFormArray
@@ -559,15 +539,6 @@ export function convertValuesRecursive(
const objectSpec = valueSpec.spec as ListValueSpecObject
convertValuesRecursive(objectSpec.spec, formGroup as UntypedFormGroup)
})
- } else if (valueSpec.subtype === 'union') {
- controls.forEach(formGroup => {
- const unionSpec = valueSpec.spec as ListValueSpecUnion
- const spec =
- unionSpec.variants[
- (formGroup as UntypedFormGroup).controls[unionSpec.tag.id].value
- ]
- convertValuesRecursive(spec, formGroup as UntypedFormGroup)
- })
}
}
})
diff --git a/frontend/projects/ui/src/app/services/patch-db/data-model.ts b/frontend/projects/ui/src/app/services/patch-db/data-model.ts
index be4d2e98c..8ea218dc8 100644
--- a/frontend/projects/ui/src/app/services/patch-db/data-model.ts
+++ b/frontend/projects/ui/src/app/services/patch-db/data-model.ts
@@ -1,4 +1,4 @@
-import { InputSpec } from 'start-sdk/types/config-types'
+import { InputSpec } from 'start-sdk/lib/config/config-types'
import { Url } from '@start9labs/shared'
import { Manifest } from '@start9labs/marketplace'
import { BasicInfo } from 'src/app/pages/developer-routes/developer-menu/form-info'
diff --git a/frontend/projects/ui/src/app/util/config-utilities.ts b/frontend/projects/ui/src/app/util/config-utilities.ts
index 207b91ecf..8a9e4afd6 100644
--- a/frontend/projects/ui/src/app/util/config-utilities.ts
+++ b/frontend/projects/ui/src/app/util/config-utilities.ts
@@ -1,4 +1,4 @@
-import { DefaultString } from 'start-sdk/types/config-types'
+import { DefaultString } from 'start-sdk/lib/config/config-types'
export class Range {
min?: number