mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
better change warnings
This commit is contained in:
@@ -17,8 +17,8 @@
|
||||
<p *ngIf="control.hasError('numberNotInRange')">
|
||||
Number not in range
|
||||
</p>
|
||||
<p *ngIf="control.hasError('invalidNumber')">
|
||||
Invalid Number
|
||||
<p *ngIf="control.hasError('notNumber')">
|
||||
{{ spec.name }} must be a number
|
||||
</p>
|
||||
</ng-container>
|
||||
|
||||
|
||||
@@ -24,25 +24,25 @@
|
||||
</h4>
|
||||
<!-- string -->
|
||||
<ion-item color="dark" *ngIf="spec.type === 'string'">
|
||||
<ion-input [type]="spec.masked && !unmasked[entry.key] ? 'password' : 'text'" [placeholder]="'Enter ' + spec.name" [formControlName]="entry.key" (ionChange)="presentAlertChangeWarning(entry.key, spec)"></ion-input>
|
||||
<ion-input [type]="spec.masked && !unmasked[entry.key] ? 'password' : 'text'" [placeholder]="'Enter ' + spec.name" [formControlName]="entry.key" (ionFocus)="presentAlertChangeWarning(key, spec)" (ionChange)="handleInputChange(spec)"></ion-input>
|
||||
<ion-button *ngIf="spec.masked" fill="clear" color="light" (click)="unmasked[entry.key] = !unmasked[entry.key]">
|
||||
<ion-icon slot="icon-only" [name]="unmasked[entry.key] ? 'eye-off-outline' : 'eye-outline'" size="small"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
<!-- number -->
|
||||
<ion-item color="dark" *ngIf="spec.type === 'number'">
|
||||
<ion-input type="tel" [placeholder]="'Enter ' + spec.name" [formControlName]="entry.key" (ionChange)="presentAlertChangeWarning(entry.key, spec)"></ion-input>
|
||||
<ion-input type="tel" [placeholder]="'Enter ' + spec.name" [formControlName]="entry.key" (ionFocus)="presentAlertChangeWarning(key, spec)" (ionChange)="handleInputChange(spec)"></ion-input>
|
||||
<ion-note *ngIf="spec.units" slot="end" color="light" style="font-size: medium;">{{ spec.units }}</ion-note>
|
||||
</ion-item>
|
||||
<!-- boolean -->
|
||||
<ion-item color="dark" *ngIf="spec.type === 'boolean'">
|
||||
<ion-label>{{ spec.name }}</ion-label>
|
||||
<ion-toggle style="--background: var(--ion-color-step-600);" slot="end" color="light" [formControlName]="entry.key" (ionChange)="presentAlertChangeWarning(entry.key, spec)"></ion-toggle>
|
||||
<ion-toggle style="--background: var(--ion-color-step-600);" slot="end" color="light" [formControlName]="entry.key" (ionChange)="handleBooleanChange(entry.key, spec)"></ion-toggle>
|
||||
</ion-item>
|
||||
<!-- enum -->
|
||||
<ion-item color="dark" *ngIf="spec.type === 'enum'">
|
||||
<ion-label>{{ spec.name }}</ion-label>
|
||||
<ion-select slot="end" placeholder="Select" [formControlName]="entry.key" [selectedText]="spec['value-names'][formGroup.get(entry.key).value]" (ionChange)="presentAlertChangeWarning(entry.key, spec)">
|
||||
<ion-select [interfaceOptions]="{ message: getWarningText(spec['change-warning']) }" slot="end" placeholder="Select" [formControlName]="entry.key" [selectedText]="spec['value-names'][formGroup.get(entry.key).value]" (ionChange)="handleInputChange(entry.key, spec)">
|
||||
<ion-select-option *ngFor="let option of spec.values" [value]="option">
|
||||
{{ spec['value-names'][option] }}
|
||||
</ion-select-option>
|
||||
@@ -134,6 +134,7 @@
|
||||
[formGroup]="abstractControl"
|
||||
[current]="current && current[entry.key] ? current[entry.key][i] : undefined"
|
||||
[unionSpec]="spec.subtype === 'union' ? spec.spec : undefined"
|
||||
(onInputChange)="updateLabel(entry.key, i, spec.spec['display-as'])"
|
||||
></form-object>
|
||||
<div style="text-align: right; padding-top: 12px;">
|
||||
<ion-button fill="clear" (click)="presentAlertDelete(entry.key, i)" color="danger">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component, Input, SimpleChange } from '@angular/core'
|
||||
import { Component, Input, Output, SimpleChange, EventEmitter } from '@angular/core'
|
||||
import { AbstractFormGroupDirective, FormArray, FormGroup } from '@angular/forms'
|
||||
import { AlertController, ModalController } from '@ionic/angular'
|
||||
import { ConfigSpec, ListValueSpecOf, ValueSpec, ValueSpecList, ValueSpecListOf, ValueSpecUnion } from 'src/app/pkg-config/config-types'
|
||||
import { AlertController, IonicSafeString, ModalController } from '@ionic/angular'
|
||||
import { ConfigSpec, ListValueSpecOf, ValueSpec, ValueSpecBoolean, ValueSpecList, ValueSpecListOf, ValueSpecNumber, ValueSpecString, ValueSpecUnion } from 'src/app/pkg-config/config-types'
|
||||
import { FormService } from 'src/app/services/form.service'
|
||||
import { Range } from 'src/app/pkg-config/config-utilities'
|
||||
import { EnumListPage } from 'src/app/modals/enum-list/enum-list.page'
|
||||
@@ -19,6 +19,7 @@ export class FormObjectComponent {
|
||||
@Input() unionSpec: ValueSpecUnion
|
||||
@Input() current: { [key: string]: any }
|
||||
@Input() showEdited: boolean = false
|
||||
@Output() onInputChange = new EventEmitter<void>()
|
||||
warningAck: { [key: string]: boolean } = { }
|
||||
unmasked: { [key: string]: boolean } = { }
|
||||
// @TODO for when we want to expand/collapse normal objects/union in addition to list ones
|
||||
@@ -88,18 +89,16 @@ export class FormObjectComponent {
|
||||
const newItem = this.formService.getListItem(listSpec, val)
|
||||
newItem.markAllAsTouched()
|
||||
arr.insert(0, newItem)
|
||||
console.log('new Item', newItem)
|
||||
if (['object', 'union'].includes(listSpec.subtype)) {
|
||||
const displayAs = (listSpec.spec as ListValueSpecOf<'object'>)['display-as']
|
||||
this.objectListInfo[key].push({
|
||||
this.objectListInfo[key].unshift({
|
||||
height: '0px',
|
||||
expanded: true,
|
||||
displayAs: displayAs ? Mustache.render(displayAs, newItem.value) : '',
|
||||
})
|
||||
|
||||
pauseFor(200).then(() => {
|
||||
const index = this.objectListInfo[key].length - 1
|
||||
this.objectListInfo[key][index].height = this.getDocSize(key)
|
||||
this.objectListInfo[key][0].height = this.getDocSize(key)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -107,7 +106,28 @@ export class FormObjectComponent {
|
||||
toggleExpand (key: string, i: number) {
|
||||
this.objectListInfo[key][i].expanded = !this.objectListInfo[key][i].expanded
|
||||
this.objectListInfo[key][i].height = this.objectListInfo[key][i].expanded ? this.getDocSize(key) : '0px'
|
||||
}
|
||||
|
||||
updateLabel (key: string, i: number, displayAs: string) {
|
||||
this.objectListInfo[key][i].displayAs = displayAs ? Mustache.render(displayAs, this.formGroup.get(key).value[i]) : ''
|
||||
}
|
||||
|
||||
getWarningText (text: string): IonicSafeString {
|
||||
return new IonicSafeString(`<ion-text color="warning">${text}</ion-text>`)
|
||||
}
|
||||
|
||||
handleInputChange (spec: ValueSpec) {
|
||||
if (['string', 'number'].includes(spec.type)) {
|
||||
this.onInputChange.emit()
|
||||
}
|
||||
}
|
||||
|
||||
handleBooleanChange (key: string, spec: ValueSpecBoolean) {
|
||||
if (spec['change-warning']) {
|
||||
const current = this.formGroup.get(key).value
|
||||
const cancelFn = () => this.formGroup.get(key).setValue(!current)
|
||||
this.presentAlertChangeWarning(key, spec, undefined, cancelFn)
|
||||
}
|
||||
}
|
||||
|
||||
async presentModalEnumList (key: string, spec: ValueSpecListOf<'enum'>, current: string[]) {
|
||||
@@ -129,7 +149,7 @@ export class FormObjectComponent {
|
||||
await modal.present()
|
||||
}
|
||||
|
||||
async presentAlertChangeWarning (key: string, spec: ValueSpec) {
|
||||
async presentAlertChangeWarning (key: string, spec: ValueSpec, okFn: Function = () => { }, cancelFn: Function = () => { }) {
|
||||
if (!spec['change-warning'] || this.warningAck[key]) return
|
||||
this.warningAck[key] = true
|
||||
|
||||
@@ -137,7 +157,20 @@ export class FormObjectComponent {
|
||||
header: 'Warning',
|
||||
subHeader: `Editing ${spec.name} has consequences:`,
|
||||
message: spec['change-warning'],
|
||||
buttons: ['Ok'],
|
||||
buttons: [
|
||||
{
|
||||
text: 'Cancel',
|
||||
handler: () => {
|
||||
cancelFn()
|
||||
},
|
||||
},
|
||||
{
|
||||
text: 'Proceed',
|
||||
handler: () => {
|
||||
okFn()
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
await alert.present()
|
||||
}
|
||||
|
||||
@@ -1102,7 +1102,7 @@ export module Mock {
|
||||
},
|
||||
'default': 'null',
|
||||
'description': 'This is not even real.',
|
||||
'change-warning': 'Be careful chnaging this!',
|
||||
'change-warning': 'Be careful changing this!',
|
||||
'values': [
|
||||
'null',
|
||||
'option1',
|
||||
|
||||
@@ -153,6 +153,7 @@ function isFullUnion (spec: ValueSpecUnion | ListValueSpecUnion): spec is ValueS
|
||||
|
||||
export function numberInRange (stringRange: string): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
if (!control.value) return null
|
||||
try {
|
||||
Range.from(stringRange).checkIncludes(control.value)
|
||||
return null
|
||||
@@ -164,15 +165,15 @@ export function numberInRange (stringRange: string): ValidatorFn {
|
||||
|
||||
export function isNumber (): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return control.value == Number(control.value) ?
|
||||
return !control.value || control.value == Number(control.value) ?
|
||||
null :
|
||||
{ invalidNumber: { value: control.value } }
|
||||
{ notNumber: { value: control.value } }
|
||||
}
|
||||
}
|
||||
|
||||
export function isInteger (): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
return control.value == Math.trunc(control.value) ?
|
||||
return !control.value || control.value == Math.trunc(control.value) ?
|
||||
null :
|
||||
{ numberNotInteger: { value: control.value } }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user