From ddf1f9bcd5666782acc9a51ed065e862e038a803 Mon Sep 17 00:00:00 2001 From: waterplea Date: Wed, 22 Mar 2023 17:05:24 +0800 Subject: [PATCH] chore: break down form-object by type, part 1 --- .../form-label/form-label.component.html | 2 +- .../form-label/form-label.component.scss | 6 +- .../form-label/form-label.component.ts | 6 +- .../form-object/form-object.module.ts | 6 + .../form-file/form-file.component.html | 40 ++++ .../form-file/form-file.component.scss | 26 +++ .../controls/form-file/form-file.component.ts | 21 +++ .../form-input/form-input.component.html | 63 +++++++ .../form-input/form-input.component.scss | 24 +++ .../form-input/form-input.component.ts | 24 +++ .../form-object/form-object.component.html | 175 +++--------------- .../form-object/form-object.component.ts | 29 +-- .../form-object/form-warning.directive.ts | 51 +++++ 13 files changed, 287 insertions(+), 186 deletions(-) create mode 100644 frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.html create mode 100644 frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.scss create mode 100644 frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.ts create mode 100644 frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.html create mode 100644 frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.scss create mode 100644 frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.ts create mode 100644 frontend/projects/ui/src/app/components/form-object/form-warning.directive.ts diff --git a/frontend/projects/ui/src/app/components/form-object/form-label/form-label.component.html b/frontend/projects/ui/src/app/components/form-object/form-label/form-label.component.html index 2095516ad..af68f02f0 100644 --- a/frontend/projects/ui/src/app/components/form-object/form-label/form-label.component.html +++ b/frontend/projects/ui/src/app/components/form-object/form-label/form-label.component.html @@ -1,6 +1,6 @@ diff --git a/frontend/projects/ui/src/app/components/form-object/form-label/form-label.component.scss b/frontend/projects/ui/src/app/components/form-object/form-label/form-label.component.scss index 99e8f5d91..9bd13bdd4 100644 --- a/frontend/projects/ui/src/app/components/form-object/form-label/form-label.component.scss +++ b/frontend/projects/ui/src/app/components/form-object/form-label/form-label.component.scss @@ -1,9 +1,11 @@ :host { display: flex; align-items: center; + font-weight: bold; } -.slot-start { +.icon { --padding-start: 0; - --padding-end: 7px; + --padding-end: 4px; + margin-right: 4px; } diff --git a/frontend/projects/ui/src/app/components/form-object/form-label/form-label.component.ts b/frontend/projects/ui/src/app/components/form-object/form-label/form-label.component.ts index 3bac36d41..f4518defb 100644 --- a/frontend/projects/ui/src/app/components/form-object/form-label/form-label.component.ts +++ b/frontend/projects/ui/src/app/components/form-object/form-label/form-label.component.ts @@ -10,9 +10,9 @@ import { AlertController } from '@ionic/angular' export class FormLabelComponent { @Input() data!: { name: string - new: boolean - edited: boolean description: string | null + edited?: boolean + new?: boolean required?: boolean newOptions?: boolean } @@ -22,7 +22,7 @@ export class FormLabelComponent { async presentAlertDescription() { const alert = await this.alertCtrl.create({ header: this.data.name, - message: this.data.description!, + message: this.data.description || '', buttons: [ { text: 'OK', diff --git a/frontend/projects/ui/src/app/components/form-object/form-object.module.ts b/frontend/projects/ui/src/app/components/form-object/form-object.module.ts index 5c05aad36..44715b4f7 100644 --- a/frontend/projects/ui/src/app/components/form-object/form-object.module.ts +++ b/frontend/projects/ui/src/app/components/form-object/form-object.module.ts @@ -16,6 +16,9 @@ import { ToEnumListDisplayPipe, ToRangePipe, } from './form-object.pipes' +import { FormFileComponent } from './form-object/controls/form-file/form-file.component' +import { FormInputComponent } from './form-object/controls/form-input/form-input.component' +import { FormWarningDirective } from './form-warning.directive' @NgModule({ declarations: [ @@ -27,6 +30,9 @@ import { ToEnumListDisplayPipe, ToElementIdPipe, ToRangePipe, + FormWarningDirective, + FormFileComponent, + FormInputComponent, ], imports: [ CommonModule, diff --git a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.html b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.html new file mode 100644 index 000000000..6cd9884bb --- /dev/null +++ b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.html @@ -0,0 +1,40 @@ + + +
+ + Browse... + + + +
+

{{ control.value.name }}

+
+ +
+
+
+
+
+

+ + {{ errors | getError }} + +

diff --git a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.scss b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.scss new file mode 100644 index 000000000..716a14c66 --- /dev/null +++ b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.scss @@ -0,0 +1,26 @@ +:host { + display: block; +} + +ion-item-divider { + text-transform: unset; + border-bottom: 1px solid + var( + --ion-item-border-color, + var(--ion-border-color, var(--ion-color-step-150, rgba(0, 0, 0, 0.13))) + ); + + --padding-top: 18px; + --padding-start: 0; + + &.error-border { + border-color: var(--ion-color-danger-shade); + --border-color: var(--ion-color-danger-shade); + } +} + +.error-message { + margin-top: 2px; + font-size: small; + color: var(--ion-color-danger); +} 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 new file mode 100644 index 000000000..83c550b44 --- /dev/null +++ b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-file/form-file.component.ts @@ -0,0 +1,21 @@ +import { Component, Input } from '@angular/core' +import { AbstractControl } from '@angular/forms' +import { ValueSpecOf } from 'start-sdk/types/config-types' + +@Component({ + selector: 'form-file', + templateUrl: './form-file.component.html', + styleUrls: ['./form-file.component.scss'], +}) +export class FormFileComponent { + @Input() spec!: ValueSpecOf<'file'> + @Input() control!: AbstractControl + + handleFileInput(e: any) { + this.control.patchValue(e.target.files[0]) + } + + clearFile() { + this.control.patchValue(null) + } +} 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 new file mode 100644 index 000000000..649d6fcbb --- /dev/null +++ b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.html @@ -0,0 +1,63 @@ + + + + + + + + + + + {{ spec.units }} + + +

+ + {{ errors | getError : $any(spec)['pattern-description'] }} + +

diff --git a/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.scss b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.scss new file mode 100644 index 000000000..4b6f0774d --- /dev/null +++ b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.scss @@ -0,0 +1,24 @@ +.label { + margin: 16px 0 6px; +} + +.input { + font-family: 'Courier New'; + font-weight: bold; + + --placeholder-font-weight: 400; + + &_redacted { + font-family: 'Redacted'; + } +} + +.units { + font-size: medium; +} + +.error-message { + margin-top: 2px; + font-size: small; + color: var(--ion-color-danger); +} 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 new file mode 100644 index 000000000..c48e4aca0 --- /dev/null +++ b/frontend/projects/ui/src/app/components/form-object/form-object/controls/form-input/form-input.component.ts @@ -0,0 +1,24 @@ +import { Component, Input, inject, Output, EventEmitter } from '@angular/core' +import { FormControl } from '@angular/forms' +import { ValueSpecOf } from 'start-sdk/types/config-types' +import { THEME } from '@start9labs/shared' +import { FormObjectComponent } from '../../form-object.component' + +@Component({ + selector: 'form-input', + templateUrl: './form-input.component.html', + styleUrls: ['./form-input.component.scss'], +}) +export class FormInputComponent { + @Input() name!: string + @Input() spec!: ValueSpecOf<'string' | 'number'> + @Input() control!: FormControl + + @Output() onInputChange = new EventEmitter() + + unmasked = false + + readonly theme$ = inject(THEME) + + constructor(readonly form: FormObjectComponent) {} +} 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 e787d7390..6004533e7 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 @@ -1,104 +1,33 @@
+ + - - -

- -

- - - - - - - - - - {{ spec.units }} - - -

- - {{ errors | getError : $any(spec)['pattern-description'] }} - -

-
+ - - - - - - {{ spec.name }} - - (New) - - - (Edited) - - - + - - - - - - - - - {{ spec.name }} - - (Edited) - - - -
- - Browse... - - - -
-

{{ control.value.name }}

-
- -
-
-
-
-
-

- - {{ errors | getError }} - -

-
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 439c5d10d..565ce020a 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 @@ -7,12 +7,7 @@ import { inject, SimpleChanges, } from '@angular/core' -import { - AbstractControl, - FormArray, - UntypedFormArray, - UntypedFormGroup, -} from '@angular/forms' +import { FormArray, UntypedFormArray, UntypedFormGroup } from '@angular/forms' import { AlertButton, AlertController, ModalController } from '@ionic/angular' import { InputSpec, @@ -240,28 +235,6 @@ export class FormObjectComponent { await alert.present() } - handleFileInput(e: any, control: AbstractControl) { - control.patchValue(e.target.files[0]) - } - - clearFile(control: AbstractControl) { - control.patchValue(null) - } - - async presentAlertDescription(name: string, description: string) { - const alert = await this.alertCtrl.create({ - header: name, - message: description || '', - buttons: [ - { - text: 'OK', - cssClass: 'enter-click', - }, - ], - }) - await alert.present() - } - private addListItem(key: string): void { const arr = this.formGroup.get(key) as UntypedFormArray const listSpec = this.objectSpec[key] as ValueSpecList 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 new file mode 100644 index 000000000..d568062f3 --- /dev/null +++ b/frontend/projects/ui/src/app/components/form-object/form-warning.directive.ts @@ -0,0 +1,51 @@ +import { Directive } from '@angular/core' +import { ValueSpec, ValueSpecUnion } from 'start-sdk/types/config-types' +import { AlertButton, AlertController } from '@ionic/angular' + +@Directive({ + selector: '[formWarning]', + exportAs: 'formWarning', +}) +export class FormWarningDirective { + private warned = false + + constructor(private readonly alertCtrl: AlertController) {} + + async onChange( + key: string, + spec: T extends ValueSpecUnion ? never : T, + okFn?: Function, + cancelFn?: Function, + ) { + if (!spec.warning || this.warned) return okFn ? okFn() : null + + this.warned = true + + const buttons: AlertButton[] = [ + { + text: 'Ok', + handler: () => { + if (okFn) okFn() + }, + cssClass: 'enter-click', + }, + ] + + if (okFn || cancelFn) { + buttons.unshift({ + text: 'Cancel', + handler: () => { + if (cancelFn) cancelFn() + }, + }) + } + + const alert = await this.alertCtrl.create({ + header: 'Warning', + subHeader: `Editing ${spec.name} has consequences:`, + message: spec.warning, + buttons, + }) + await alert.present() + } +}