mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
183 lines
5.3 KiB
TypeScript
183 lines
5.3 KiB
TypeScript
import { Component, Input, ViewChild } from '@angular/core'
|
|
import { AlertController, ModalController, IonContent, LoadingController } from '@ionic/angular'
|
|
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
|
import { isEmptyObject, Recommendation } from 'src/app/util/misc.util'
|
|
import { wizardModal } from 'src/app/components/install-wizard/install-wizard.component'
|
|
import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards'
|
|
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
|
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
|
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
|
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
|
import { FormGroup } from '@angular/forms'
|
|
import { FormService } from 'src/app/services/form.service'
|
|
|
|
@Component({
|
|
selector: 'app-config',
|
|
templateUrl: './app-config.page.html',
|
|
styleUrls: ['./app-config.page.scss'],
|
|
})
|
|
export class AppConfigPage {
|
|
@Input() pkgId: string
|
|
loadingText: string | undefined
|
|
configSpec: ConfigSpec
|
|
configForm: FormGroup
|
|
current: object
|
|
hasConfig = false
|
|
|
|
rec: Recommendation | null = null
|
|
showRec = true
|
|
openRec = false
|
|
|
|
@ViewChild(IonContent) content: IonContent
|
|
|
|
constructor (
|
|
private readonly wizardBaker: WizardBaker,
|
|
private readonly embassyApi: ApiService,
|
|
private readonly errToast: ErrorToastService,
|
|
private readonly loadingCtrl: LoadingController,
|
|
private readonly alertCtrl: AlertController,
|
|
private readonly modalCtrl: ModalController,
|
|
private readonly formService: FormService,
|
|
public readonly patch: PatchDbService,
|
|
) { }
|
|
|
|
async ngOnInit () {
|
|
const rec = history.state?.configRecommendation as Recommendation
|
|
|
|
try {
|
|
this.loadingText = 'Loading Config'
|
|
const { spec, config } = await this.embassyApi.getPackageConfig({ id: this.pkgId })
|
|
|
|
let depConfig: object
|
|
if (rec) {
|
|
this.loadingText = `Setting properties to accommodate ${rec.dependentTitle}...`
|
|
depConfig = await this.embassyApi.dryConfigureDependency({ 'dependency-id': this.pkgId, 'dependent-id': rec.dependentId })
|
|
}
|
|
this.setConfig(spec, config, depConfig)
|
|
} catch (e) {
|
|
this.errToast.present(e)
|
|
} finally {
|
|
this.loadingText = undefined
|
|
}
|
|
}
|
|
|
|
ngAfterViewInit () {
|
|
this.content.scrollToPoint(undefined, 1)
|
|
}
|
|
|
|
setConfig (spec: ConfigSpec, config: object, depConfig?: object) {
|
|
this.configSpec = spec
|
|
this.current = config
|
|
this.hasConfig = !isEmptyObject(config)
|
|
this.configForm = this.formService.createForm(spec, { ...config, ...depConfig })
|
|
this.configForm.markAllAsTouched()
|
|
|
|
if (depConfig) {
|
|
this.markDirtyRecursive(this.configForm, depConfig)
|
|
}
|
|
}
|
|
|
|
markDirtyRecursive (group: FormGroup, config: object) {
|
|
Object.keys(config).forEach(key => {
|
|
const next = group.get(key)
|
|
if (!next) throw new Error('Dependency config not compatible with service version. Please contact support')
|
|
const newVal = config[key]
|
|
// check if val is an object
|
|
if (newVal && typeof newVal === 'object' && !Array.isArray(newVal)) {
|
|
this.markDirtyRecursive(next as FormGroup, newVal)
|
|
} else {
|
|
let val1 = group.get(key).value
|
|
let val2 = config[key]
|
|
if (Array.isArray(newVal)) {
|
|
val1 = JSON.stringify(val1)
|
|
val2 = JSON.stringify(val2)
|
|
}
|
|
if (val1 != val2) next.markAsDirty()
|
|
}
|
|
})
|
|
}
|
|
|
|
resetDefaults () {
|
|
this.configForm = this.formService.createForm(this.configSpec)
|
|
this.markDirtyRecursive(this.configForm, this.current)
|
|
}
|
|
|
|
dismissRec () {
|
|
this.showRec = false
|
|
}
|
|
|
|
async dismiss () {
|
|
if (this.configForm?.dirty) {
|
|
await this.presentAlertUnsaved()
|
|
} else {
|
|
this.modalCtrl.dismiss()
|
|
}
|
|
}
|
|
|
|
async save (pkg: PackageDataEntry) {
|
|
if (this.configForm.invalid) {
|
|
document.getElementsByClassName('validation-error')[0].parentElement.parentElement.scrollIntoView({ behavior: 'smooth' })
|
|
return
|
|
}
|
|
|
|
const loader = await this.loadingCtrl.create({
|
|
spinner: 'lines',
|
|
message: `Saving config...`,
|
|
cssClass: 'loader',
|
|
})
|
|
await loader.present()
|
|
|
|
const config = this.configForm.value
|
|
|
|
try {
|
|
const breakages = await this.embassyApi.drySetPackageConfig({
|
|
id: pkg.manifest.id,
|
|
config,
|
|
})
|
|
|
|
if (!isEmptyObject(breakages.length)) {
|
|
const { cancelled } = await wizardModal(
|
|
this.modalCtrl,
|
|
this.wizardBaker.configure({
|
|
pkg,
|
|
breakages,
|
|
}),
|
|
)
|
|
if (cancelled) return
|
|
}
|
|
|
|
await this.embassyApi.setPackageConfig({
|
|
id: pkg.manifest.id,
|
|
config,
|
|
})
|
|
this.modalCtrl.dismiss()
|
|
} catch (e) {
|
|
this.errToast.present(e)
|
|
} finally {
|
|
loader.dismiss()
|
|
}
|
|
}
|
|
|
|
private async presentAlertUnsaved () {
|
|
const alert = await this.alertCtrl.create({
|
|
header: 'Unsaved Changes',
|
|
message: 'You have unsaved changes. Are you sure you want to leave?',
|
|
buttons: [
|
|
{
|
|
text: 'Cancel',
|
|
role: 'cancel',
|
|
},
|
|
{
|
|
text: `Leave`,
|
|
handler: () => {
|
|
this.modalCtrl.dismiss()
|
|
},
|
|
cssClass: 'enter-click',
|
|
},
|
|
],
|
|
})
|
|
await alert.present()
|
|
}
|
|
}
|
|
|