diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2b4c52c3561d8459c70b9b0400360eb77d58709b..eec4be44e1c1f6d0b17b069bfadd0da927d64adf 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,7 +2,6 @@ variables: BASE_HREF: nshmp GITLAB_TOKEN: '${CI_JOB_TOKEN}' IMAGE_NAME: ${CODE_REGISTRY_IMAGE}/${CI_PROJECT_NAME}:${ENVIRONMENT}-${CI_COMMIT_SHORT_SHA} - NODE_IMAGE: ${CODE_REGISTRY_IMAGE}/${CI_PROJECT_NAME}:${CI_COMMIT_REF_SLUG}--node UPSTREAM_PATH: ghsc/nshmp/nshmp-apps image: ${CI_REGISTRY}/devops/images/usgs/node:20 @@ -75,10 +74,10 @@ default: # Docker in Docker ## .dind: - image: ${CI_REGISTRY}/devops/images/docker:20 + image: ${CI_REGISTRY}/devops/images/usgs/docker:20 services: - alias: docker - name: ${CI_REGISTRY}/devops/images/docker:20-dind + name: ${CI_REGISTRY}/devops/images/usgs/docker:20-dind variables: DOCKER_DRIVER: overlay2 @@ -150,26 +149,6 @@ Init: - npm ci stage: init -Build Node Image: - image: ${CI_REGISTRY}/devops/images/docker:20 - script: - - | - docker build \ - --build-arg FROM_IMAGE=${CI_REGISTRY}/devops/images/usgs/node:20 \ - --file ".gitlab/Dockerfile" \ - --pull \ - --tag ${NODE_IMAGE} \ - . - - docker push ${NODE_IMAGE} - services: - - alias: docker - name: ${CI_REGISTRY}/devops/images/docker:20-dind - stage: init - tags: - - build - variables: - DOCKER_DRIVER: overlay2 - #### # Stage: Build #### @@ -178,13 +157,10 @@ Build Project: artifacts: paths: - dist - before_script: - - git config --global --add safe.directory '*' - image: ${NODE_IMAGE} needs: - Init - - Build Node Image script: + - apt-get install -y git - npm run build:prod stage: build diff --git a/.gitlab/Dockerfile b/.gitlab/Dockerfile deleted file mode 100644 index c5a2d0ec80bd0eb443ebc53f3aa4a589b0e4f30c..0000000000000000000000000000000000000000 --- a/.gitlab/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG FROM_IMAGE=code.usgs.gov:5001/devops/images/usgs/node:20 - -FROM ${FROM_IMAGE} - -USER root - -RUN apt-get install -y git - -USER usgs-user diff --git a/projects/nshmp-apps/src/app/gmm/distance/components/control-panel/control-panel.component.ts b/projects/nshmp-apps/src/app/gmm/distance/components/control-panel/control-panel.component.ts index e4718bf16a53f4239006f169dc495e5e05818e97..de3142140756ae35c94db34eb28f1243eaf7a97d 100644 --- a/projects/nshmp-apps/src/app/gmm/distance/components/control-panel/control-panel.component.ts +++ b/projects/nshmp-apps/src/app/gmm/distance/components/control-panel/control-panel.component.ts @@ -115,12 +115,6 @@ export class ControlPanelComponent implements OnInit, OnDestroy { this.subs.push( combineLatest([ this.controls.dip.valueChanges, - this.controls.width.valueChanges, - ]).subscribe(() => this.updatePlots()) - ); - - this.subs.push( - combineLatest([ this.controls.imt.valueChanges, this.controls.Mw.valueChanges, this.controls.MwMulti.valueChanges, @@ -129,6 +123,7 @@ export class ControlPanelComponent implements OnInit, OnDestroy { this.controls.z1p0.valueChanges, this.controls.z2p5.valueChanges, this.controls.zSed.valueChanges, + this.controls.width.valueChanges, ]).subscribe(() => this.facade.resetState()) ); } diff --git a/projects/nshmp-apps/src/app/gmm/gmm.routes.ts b/projects/nshmp-apps/src/app/gmm/gmm.routes.ts index 52138a14c49bbf2b5051944fdb2864fdffa313ed..b20f1a8722b2dd854e9bb902f0d708824a12ee25 100644 --- a/projects/nshmp-apps/src/app/gmm/gmm.routes.ts +++ b/projects/nshmp-apps/src/app/gmm/gmm.routes.ts @@ -2,8 +2,6 @@ import {Routes} from '@angular/router'; import {provideEffects} from '@ngrx/effects'; import {provideState} from '@ngrx/store'; -import {MagnitudeAppEffects} from './magnitude/state/app.effects'; -import {magnitudeAppFeature} from './magnitude/state/app.reducer'; import {SpectraAppEffects} from './spectra/state/app.effects'; import {spectraAppFeature} from './spectra/state/app.reducer'; @@ -18,10 +16,6 @@ const routes: Routes = [ loadComponent: () => import('./magnitude/app.component').then(com => com.AppComponent), path: 'magnitude', - providers: [ - provideState(magnitudeAppFeature), - provideEffects(MagnitudeAppEffects), - ], }, { loadComponent: () => diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.html b/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.html index 3ce3d99ca6c33d655dadba43bc0af83b84cc962f..045a0871571f3b574e62239774a18219d187d0e7 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.html +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.html @@ -10,15 +10,15 @@ <mat-tab labelClass="medians-tab" label="Medians" - [disabled]="(hasData$ | async) === false" + [disabled]="hasData() === false" > <ng-template matTabContent> - <nshmp-lib-ng-export-data-table - [table]="meanTable$ | async" + <nshmp-lib-no-ngrx-export-data-table + [table]="meanTable()" filename="gmm-magnitude-means.csv" buttonText="Export Means as CSV" /> - <nshmp-lib-ng-data-table [table]="meanTable$ | async" /> + <nshmp-lib-no-ngrx-data-table [table]="meanTable()" /> </ng-template> </mat-tab> @@ -26,15 +26,15 @@ <mat-tab labelClass="sigmas-tab" label="Sigmas" - [disabled]="(hasData$ | async) === false" + [disabled]="hasData() === false" > <ng-template matTabContent> - <nshmp-lib-ng-export-data-table - [table]="sigmaTable$ | async" + <nshmp-lib-no-ngrx-export-data-table + [table]="sigmaTable()" filename="gmm-magnitude-sigmas.csv" buttonText="Export Sigmas as CSV" /> - <nshmp-lib-ng-data-table [table]="sigmaTable$ | async" /> + <nshmp-lib-no-ngrx-data-table [table]="sigmaTable()" /> </ng-template> </mat-tab> </mat-tab-group> diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.spec.ts index 4a22de1da0a6214e9c09b4c04a17d50bc64f8a15..3b3a0a2f34ce2579c60042f19a6cf790b5a04199 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.spec.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.spec.ts @@ -1,6 +1,6 @@ +import {provideHttpClient} from '@angular/common/http'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; import {provideNoopAnimations} from '@angular/platform-browser/animations'; -import {provideMockStore} from '@ngrx/store/testing'; import {ContentComponent} from './content.component'; @@ -11,10 +11,7 @@ describe('ContentComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [ContentComponent], - providers: [ - provideMockStore({initialState: {}}), - provideNoopAnimations(), - ], + providers: [provideNoopAnimations(), provideHttpClient()], teardown: {destroyAfterEach: false}, }).compileComponents(); })); diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.ts index b67a804fd62fdb6b5a8d71f04bff36d50d3c73af..f8561f3c85b6be4dda5cdf774d90552e03a82889 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.ts @@ -1,12 +1,11 @@ import {AsyncPipe} from '@angular/common'; -import {Component} from '@angular/core'; +import {Component, computed} from '@angular/core'; import {MatTab, MatTabContent, MatTabGroup} from '@angular/material/tabs'; -import {gmmUtils} from '@ghsc/nshmp-lib-ng/gmm'; +import {gmmUtils} from '@ghsc/nshmp-lib-no-ngrx/gmm'; import { NshmpLibNgDataTableComponent, NshmpLibNgExportDataTableComponent, -} from '@ghsc/nshmp-lib-ng/nshmp'; -import {map} from 'rxjs/operators'; +} from '@ghsc/nshmp-lib-no-ngrx/nshmp'; import {AppFacade} from '../../state/app.facade'; import {PlotsComponent} from '../plots/plots.component'; @@ -41,23 +40,29 @@ export class ContentComponent { sigmaExp = false; /** Whether service has been called and data exists */ - hasData$ = this.facade.serviceResponse$.pipe( - map(responseSpectra => responseSpectra?.length > 0) - ); + hasData = computed(() => this.facade.serviceResponse()?.length > 0); /** Table data for mean data */ - meanTable$ = this.facade.meanPlotState$.pipe( - map(plot => - gmmUtils.plotToTable(plot.plotData, this.medianExp, this.commonXValues) - ) - ); + meanTable = computed(() => { + const plot = this.facade.meanPlotState(); + + return gmmUtils.plotToTable( + plot.plotData, + this.medianExp, + this.commonXValues + ); + }); /** Table data for sigma table */ - sigmaTable$ = this.facade.sigmaPlotState$.pipe( - map(plot => - gmmUtils.plotToTable(plot.plotData, this.sigmaExp, this.commonXValues) - ) - ); + sigmaTable = computed(() => { + const plot = this.facade.sigmaPlotState(); + + return gmmUtils.plotToTable( + plot.plotData, + this.medianExp, + this.commonXValues + ); + }); constructor(public facade: AppFacade) {} } diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.html b/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.html index f9fb679e70e2a9740bc7d4b489983a159b5ef424..4fa3ff227cd27be54c0befba86f5b96f6e3349b3 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.html +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.html @@ -1,70 +1,65 @@ <!-- Ground Motion vs. Magnitude Conrol Panel --> -@if (form$ | async) { - <form - class="settings-section control-panel height-full overflow-auto" - [ngrxFormState]="form$ | async" - (submit)="onSubmit()" - novalidate - > - <mat-form-field - class="grid-col-12 multi-select-parameter-menu padding-top-1" - > - <mat-label>Multi-Selectable Parameter</mat-label> - <mat-select - [ngrxFormControlState]="(controls$ | async)?.multiSelectableParam" - > - <mat-option value="gmm">Ground Motion Models</mat-option> - <mat-option value="vs30">V30</mat-option> - </mat-select> - </mat-form-field> +<form + class="settings-section control-panel height-full overflow-auto" + [formGroup]="form" + (submit)="onSubmit()" + novalidate +> + <mat-form-field class="grid-col-12 multi-select-parameter-menu padding-top-1"> + <mat-label>Multi-Selectable Parameter</mat-label> + <mat-select [formControl]="controls.multiSelectableParam"> + <mat-option value="gmm">Ground Motion Models</mat-option> + <mat-option value="vs30">V30</mat-option> + </mat-select> + </mat-form-field> - <!-- GMM menu --> - <nshmp-lib-ng-gmm-menu - [gmmControlState]="(controls$ | async)?.gmmSource" - [gmmGroupTypeState]="(controls$ | async)?.gmmGroupType" - [multiple]="(controls$ | async)?.multiSelectableParam.value === 'gmm'" - [parameters]="parameters$ | async" + <!-- GMM menu --> + @if (parameters()) { + <nshmp-lib-no-ngrx-gmm-menu + [gmmControl]="controls.gmmSource" + [gmmGroupTypeControl]="controls.gmmGroupType" + [multiple]="controls.multiSelectableParam.value === 'gmm'" + [parameters]="parameters()" + [imtControl]="controls.imt" + [supportedImts]="supportedImts()" /> + } - <!-- IMT select menu --> - <mat-form-field class="grid-col-12 imt-select"> - <mat-label>Intensity Measure Type</mat-label> - <mat-select - #imtSelectEl - [ngrxFormControlState]="(controls$ | async)?.imt" - > - @if ((gmmSelected$ | async) === false) { - <mat-option selected="true" value="default"> - --- Choose a GMM --- - </mat-option> - } - @for (imt of supportedImts$ | async; track imt) { - <mat-option [value]="imt.value"> - {{ imt.display }} - </mat-option> - } - </mat-select> - </mat-form-field> + <!-- IMT select menu --> + <mat-form-field class="grid-col-12 imt-select"> + <mat-label>Intensity Measure Type</mat-label> + <mat-select #imtSelectEl [formControl]="controls.imt"> + @if (gmmSelected === false) { + <mat-option selected="true" value="default"> + --- Choose a GMM --- + </mat-option> + } + @for (imt of supportedImts(); track imt) { + <mat-option [value]="imt.value"> + {{ imt.display }} + </mat-option> + } + </mat-select> + </mat-form-field> - <app-event-parameters /> + <app-event-parameters /> - <app-source-parameters /> + <app-source-parameters /> - <app-path-parameters /> + <app-path-parameters /> - <app-site-parameters /> + <app-site-parameters /> - <nshmp-lib-ng-gmm-plot-options-control-panel - [showEpistemicFormControl]="(controls$ | async)?.showEpistemicUncertainty" - /> + <nshmp-lib-no-ngrx-gmm-plot-options-control-panel + [showEpistemicFormControl]="controls?.showEpistemicUncertainty" + /> - <div class="padding-y-3"></div> + <div class="padding-y-3"></div> - <nshmp-lib-ng-control-panel-buttons - [plotDisabled]="(form$ | async)?.isInvalid" - [serviceCallInfo]="serviceCallInfo$ | async" - [resetDisabled]="(form$ | async)?.isPristine" - (resetClick)="facade.resetControlPanel()" - /> - </form> -} + <nshmp-lib-no-ngrx-control-panel-buttons + [plotDisabled]="form.invalid" + [serviceCallInfo]="serviceCallInfo()" + [resetDisabled]="form.pristine" + (resetClick)="facade.resetControlPanel()" + /> +</form> diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.spec.ts index dd4d4d08659740fce235ba99d0bc1cc299c66fad..524a65d032356a098ecd8f442e66aa0be076a395 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.spec.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.spec.ts @@ -1,6 +1,6 @@ import {provideHttpClient} from '@angular/common/http'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; -import {provideMockStore} from '@ngrx/store/testing'; +import {provideNoopAnimations} from '@angular/platform-browser/animations'; import {ControlPanelComponent} from './control-panel.component'; @@ -11,7 +11,7 @@ describe('ControlPanelComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [ControlPanelComponent], - providers: [provideMockStore({initialState: {}}), provideHttpClient()], + providers: [provideHttpClient(), provideNoopAnimations()], teardown: {destroyAfterEach: false}, }).compileComponents(); })); diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.ts index 6f463e6b51bc4bd291caa49bd18cb7285aadead8..b83e99feeccf022a82f0c7570685cb0454ac4201 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.ts @@ -1,21 +1,23 @@ import {AsyncPipe} from '@angular/common'; -import {Component} from '@angular/core'; +import {Component, computed, OnDestroy, OnInit} from '@angular/core'; +import {ReactiveFormsModule} from '@angular/forms'; import {MatOption} from '@angular/material/core'; import {MatFormField, MatLabel} from '@angular/material/form-field'; import {MatSelect} from '@angular/material/select'; import { + GmmFormControlIds, + gmmUtils, NshmpLibNgGmmMenuComponent, NshmpLibNgGmmPlotOptionsControlPanelComponent, -} from '@ghsc/nshmp-lib-ng/gmm'; +} from '@ghsc/nshmp-lib-no-ngrx/gmm'; import { NshmpLibNgControlPanelButtonsComponent, - NshmpNgrxFormsModule, NshmpService, -} from '@ghsc/nshmp-lib-ng/nshmp'; -import {unbox} from 'ngrx-forms'; -import {map} from 'rxjs/operators'; +} from '@ghsc/nshmp-lib-no-ngrx/nshmp'; +import {Subscription} from 'rxjs'; import {AppFacade} from '../../state/app.facade'; +import {DEFAULT_FORM_VALUES} from '../../utils/app.default-values'; import {EventParametersComponent} from '../event-parameters/event-parameters.component'; import {PathParametersComponent} from '../path-parameters/path-parameters.component'; import {SiteParametersComponent} from '../site-parameters/site-parameters.component'; @@ -38,41 +40,67 @@ import {SourceParametersComponent} from '../source-parameters/source-parameters. PathParametersComponent, SiteParametersComponent, AsyncPipe, - NshmpNgrxFormsModule, + ReactiveFormsModule, ], selector: 'app-control-panel', standalone: true, styleUrl: './control-panel.component.scss', templateUrl: './control-panel.component.html', }) -export class ControlPanelComponent { +export class ControlPanelComponent implements OnInit, OnDestroy { /** Form controls state */ - controls$ = this.facade.controlForm$.pipe(map(form => form.controls)); + controls = this.facade.formGroup.controls; /** Control panel form field state */ - form$ = this.facade.controlForm$; + form = this.facade.formGroup; /** Whether a GMM has been selected */ - gmmSelected$ = this.controls$.pipe( - map(controls => unbox(controls.gmmSource.value).length > 0) - ); + gmmSelected = this.controls.gmmSource.getRawValue()?.length > 0; /** Usage parameters */ - parameters$ = this.facade.usage$.pipe( - map(usage => usage?.response?.parameters) - ); + parameters = computed(() => this.facade.usage()?.response.parameters); /** Service call info state */ - serviceCallInfo$ = this.facade.serviceCallInfo$; + serviceCallInfo = this.facade.serviceCallInfo; /** Supported IMTs based on GMMs selected */ - supportedImts$ = this.facade.supportedImts$; + supportedImts = this.facade.supportedImts; + + private subs: Subscription[] = []; constructor( public facade: AppFacade, private nshmpService: NshmpService ) {} + ngOnInit(): void { + this.subs.push( + this.controls.gmmSource.valueChanges.subscribe(() => { + this.onGmmSource(); + }) + ); + + this.subs.push( + this.controls.multiSelectableParam.valueChanges.subscribe(() => + this.onMultiSelectableParam() + ) + ); + + this.subs.push( + this.controls.showEpistemicUncertainty.valueChanges.subscribe(() => + this.onShowEpistemicUncertainty() + ) + ); + + this.subs.push( + this.controls.imt.valueChanges.subscribe(() => this.facade.resetState()) + ); + } + + ngOnDestroy(): void { + this.subs.forEach(sub => sub?.unsubscribe()); + } + /** * On form submit. */ @@ -80,4 +108,63 @@ export class ControlPanelComponent { this.facade.callService(); this.nshmpService.selectPlotControl(); } + + private onGmmSource() { + const formValues = this.form.getRawValue(); + + if ( + !this.facade.state().usageResponse || + formValues.gmmSource.length === 0 + ) { + this.controls.imt.patchValue(gmmUtils.imtPlaceHolder().value); + this.facade.updateState({ + supportedImts: [], + }); + return; + } + + const supportedImts = gmmUtils.getSupportedImts( + formValues.gmmSource, + this.facade.state().usageResponse + ); + + this.facade.updateState({ + supportedImts, + }); + + const imt = [...supportedImts].shift(); + + this.controls.imt.patchValue(imt?.value); + this.facade.resetState(); + } + + private onMultiSelectableParam(): void { + if (!this.facade.state().usageResponse) { + return; + } + + const {multiSelectableParam} = this.form.getRawValue(); + const parameters = this.facade.state().usageResponse.response.parameters; + + if (multiSelectableParam === GmmFormControlIds.MW) { + this.controls.Mw.setValue(parameters.Mw.value as number); + this.controls.MwMulti.setValue([]); + } else if (multiSelectableParam === GmmFormControlIds.VS30) { + this.controls.vs30.setValue(parameters.vs30.value as number); + this.controls.vs30Multi.setValue([]); + } + + this.controls.gmmSource.setValue([]); + this.controls.gmmSource.markAsPristine(); + this.controls.imt.setValue(DEFAULT_FORM_VALUES.imt); + this.facade.resetState(); + } + + private onShowEpistemicUncertainty(): void { + this.facade.createPlots(); + } + + private updatePlots(): void { + this.facade.createPlots(); + } } diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.html b/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.html index bab977bfdbfec61be3892c9b57fa8943fab23a2e..f0a3b452d1ec8ee71b36922526f704fded66357d 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.html +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.html @@ -1,64 +1,62 @@ <!-- Event parameters --> -@if (form$ | async) { - <div class="settings-subsection control-panel"> - <mat-label class="settings-subsection--label">Event Parameters</mat-label> - <div class="settings-subsection--section grid-row grid-gap-sm"> - <!-- Event parameters: mMin input --> - <mat-form-field class="grid-col-4 mmin-input"> - <mat-label>Minimum Mw</mat-label> - <input - matInput - [max]="(parameters$ | async)?.mMin?.max" - [min]="(parameters$ | async)?.mMin?.min" - [ngrxFormControlState]="(controls$ | async)?.mMin" - step="0.1" - type="number" - /> - <mat-error> - [ - {{ (parameters$ | async)?.mMin?.min }}, - {{ (parameters$ | async)?.mMin?.max }} - ] - </mat-error> - </mat-form-field> +<div class="settings-subsection control-panel"> + <mat-label class="settings-subsection--label">Event Parameters</mat-label> + <div class="settings-subsection--section grid-row grid-gap-sm"> + <!-- Event parameters: mMin input --> + <mat-form-field class="grid-col-4 mmin-input"> + <mat-label>Minimum Mw</mat-label> + <input + matInput + [max]="parameters()?.mMin?.max" + [min]="parameters()?.mMin?.min" + [formControl]="controls.mMin" + step="0.1" + type="number" + /> + <mat-error> + [ + {{ parameters()?.mMin?.min }}, + {{ parameters()?.mMin?.max }} + ] + </mat-error> + </mat-form-field> - <!-- Event parameters: mMax input --> - <mat-form-field class="grid-col-4 mmax-input"> - <mat-label>Maximum Mw</mat-label> - <input - matInput - [max]="(parameters$ | async)?.mMax?.max" - [min]="(parameters$ | async)?.mMax?.min" - [ngrxFormControlState]="(controls$ | async)?.mMax" - step="0.1" - type="number" - /> - <mat-error> - [ - {{ (parameters$ | async)?.mMax?.min }}, - {{ (parameters$ | async)?.mMax?.max }} - ] - </mat-error> - </mat-form-field> + <!-- Event parameters: mMax input --> + <mat-form-field class="grid-col-4 mmax-input"> + <mat-label>Maximum Mw</mat-label> + <input + matInput + [max]="parameters()?.mMax?.max" + [min]="parameters()?.mMax?.min" + [formControl]="controls.mMax" + step="0.1" + type="number" + /> + <mat-error> + [ + {{ parameters()?.mMax?.min }}, + {{ parameters()?.mMax?.max }} + ] + </mat-error> + </mat-form-field> - <!-- Event parameters: Step input --> - <mat-form-field class="grid-col-4 mstep-input"> - <mat-label>Mw Step</mat-label> - <input - matInput - [max]="(parameters$ | async)?.step?.max" - [min]="(parameters$ | async)?.step?.min" - [ngrxFormControlState]="(controls$ | async)?.step" - step="0.1" - type="number" - /> - <mat-error> - [ - {{ (parameters$ | async)?.step?.min }}, - {{ (parameters$ | async)?.step?.max }} - ] - </mat-error> - </mat-form-field> - </div> + <!-- Event parameters: Step input --> + <mat-form-field class="grid-col-4 mstep-input"> + <mat-label>Mw Step</mat-label> + <input + matInput + [max]="parameters()?.step?.max" + [min]="parameters()?.step?.min" + [formControl]="controls.step" + step="0.1" + type="number" + /> + <mat-error> + [ + {{ parameters()?.step?.min }}, + {{ parameters()?.step?.max }} + ] + </mat-error> + </mat-form-field> </div> -} +</div> diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.spec.ts index c46328c70608250311f475dd748fd7ecc2811806..ea17eb0a689678f814d7d89a0f36c0a858dc503e 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.spec.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.spec.ts @@ -1,5 +1,6 @@ +import {provideHttpClient} from '@angular/common/http'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; -import {provideMockStore} from '@ngrx/store/testing'; +import {provideNoopAnimations} from '@angular/platform-browser/animations'; import {EventParametersComponent} from './event-parameters.component'; @@ -10,7 +11,7 @@ describe('EventParametersComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [EventParametersComponent], - providers: [provideMockStore({initialState: {}})], + providers: [provideHttpClient(), provideNoopAnimations()], teardown: {destroyAfterEach: false}, }).compileComponents(); })); diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.ts index b9494f380b2491a2df639ac023fb27b2718a3f30..ddff305604521d9796a5f477c7376296214595e9 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.ts @@ -1,9 +1,8 @@ -import {AsyncPipe} from '@angular/common'; -import {Component} from '@angular/core'; +import {Component, computed, OnDestroy, OnInit} from '@angular/core'; +import {ReactiveFormsModule} from '@angular/forms'; import {MatError, MatFormField, MatLabel} from '@angular/material/form-field'; import {MatInput} from '@angular/material/input'; -import {NshmpNgrxFormsModule} from '@ghsc/nshmp-lib-ng/nshmp'; -import {map} from 'rxjs/operators'; +import {combineLatest, Subscription} from 'rxjs'; import {AppFacade} from '../../state/app.facade'; @@ -11,30 +10,35 @@ import {AppFacade} from '../../state/app.facade'; * Control panel form fields for GMM event parameters. */ @Component({ - imports: [ - MatLabel, - MatFormField, - MatInput, - MatError, - AsyncPipe, - NshmpNgrxFormsModule, - ], + imports: [MatLabel, MatFormField, MatInput, MatError, ReactiveFormsModule], selector: 'app-event-parameters', standalone: true, styleUrl: './event-parameters.component.scss', templateUrl: './event-parameters.component.html', }) -export class EventParametersComponent { +export class EventParametersComponent implements OnInit, OnDestroy { /** Form controls state */ - controls$ = this.facade.controlForm$.pipe(map(form => form?.controls)); + controls = this.facade.formGroup.controls; /** Control panel form field state */ - form$ = this.facade.controlForm$; + form = this.facade.formGroup; /** Usage parameters */ - parameters$ = this.facade.usage$.pipe( - map(usage => usage?.response?.parameters) - ); + parameters = computed(() => this.facade.usage()?.response.parameters); + + private valueSubscription = new Subscription(); constructor(private facade: AppFacade) {} + + ngOnInit(): void { + this.valueSubscription = combineLatest([ + this.controls.mMax.valueChanges, + this.controls.mMin.valueChanges, + this.controls.step.valueChanges, + ]).subscribe(() => this.facade.resetState()); + } + + ngOnDestroy(): void { + this.valueSubscription.unsubscribe(); + } } diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.html b/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.html index f0044425a8853c03dd8b56e38ccfb9780f527e2d..06e1589fbac83e95c2d39ec59c7075d4e20550ed 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.html +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.html @@ -1,97 +1,94 @@ -@if (form$ | async; as form) { - <div class="grid-row parameter-summary"> - <div class="grid-col-12 tablet-lg:grid-col-6"> - <mat-list class="parameter-list"> - <mat-list-item> - <span class="parameter">Ground Motion Models</span>: - </mat-list-item> - - @for (gmmSource of unbox(form?.value?.gmmSource); track gmmSource) { - <mat-list-item class="indent-list font-small"> - {{ gmmSource.gmm.display }} - </mat-list-item> - } - </mat-list> - </div> +<div class="grid-row parameter-summary"> + <div class="grid-col-12 tablet-lg:grid-col-6"> + <mat-list class="parameter-list"> + <mat-list-item> + <span class="parameter">Ground Motion Models</span>: + </mat-list-item> - <div class="grid-col-12 tablet-lg:grid-col-4"> - <mat-list class="parameter-list"> - <mat-list-item> - <span class="parameter">IMT</span>: - {{ imtIdToDisplay(form?.value?.imt) }} + @for (gmmSource of form?.value?.gmmSource; track gmmSource) { + <mat-list-item class="indent-list font-small"> + {{ gmmSource.gmm.display }} </mat-list-item> + } + </mat-list> + </div> - <mat-list-item> - <span class="parameter">Mw Range</span>: [{{ form?.value?.mMin }}, - {{ form?.value?.mMax }}] - </mat-list-item> + <div class="grid-col-12 tablet-lg:grid-col-4"> + <mat-list class="parameter-list"> + <mat-list-item> + <span class="parameter">IMT</span>: + {{ imtIdToDisplay(form?.value?.imt) }} + </mat-list-item> - <mat-list-item> - <span class="parameter">Mw Step</span>: - {{ form?.value?.step }} - </mat-list-item> + <mat-list-item> + <span class="parameter">Mw Range</span>: [{{ form?.value?.mMin }}, + {{ form?.value?.mMax }}] + </mat-list-item> - <mat-list-item> - <span class="parameter"> Z<sub>TOR</sub> </span>: - {{ form?.value?.zTor }} km - </mat-list-item> + <mat-list-item> + <span class="parameter">Mw Step</span>: + {{ form?.value?.step }} + </mat-list-item> - <mat-list-item> - <span class="parameter">Dip</span>: {{ form?.value?.dip }}° - </mat-list-item> + <mat-list-item> + <span class="parameter"> Z<sub>TOR</sub> </span>: + {{ form?.value?.zTor }} km + </mat-list-item> - <mat-list-item> - <span class="parameter">Width</span>: {{ form?.value?.width }} km - </mat-list-item> - </mat-list> - </div> + <mat-list-item> + <span class="parameter">Dip</span>: {{ form?.value?.dip }}° + </mat-list-item> - <div class="grid-col-12 tablet-lg:grid-col-2"> - <mat-list class="parameter-list"> - <mat-list-item> - <span class="parameter"> Distance</span>: - {{ form?.value?.distance }} km - </mat-list-item> + <mat-list-item> + <span class="parameter">Width</span>: {{ form?.value?.width }} km + </mat-list-item> + </mat-list> + </div> + + <div class="grid-col-12 tablet-lg:grid-col-2"> + <mat-list class="parameter-list"> + <mat-list-item> + <span class="parameter"> Distance</span>: {{ form?.value?.distance }} km + </mat-list-item> - @if (form.value.multiSelectableParam === GmmFormControlIds.VS30) { - <mat-list-item> <span class="parameter">Vs30</span>: </mat-list-item> - @for (vs30 of unbox(form?.value?.vs30Multi); track vs30) { - <mat-list-item class="indent-list"> - {{ vs30 }} - <sup> m</sup>/<sub>s</sub> - </mat-list-item> - } - } @else { - <mat-list-item> - <span class="parameter">Vs30</span>: {{ form?.value?.vs30 }} + @if (form.value.multiSelectableParam === GmmFormControlIds.VS30) { + <mat-list-item> <span class="parameter">Vs30</span>: </mat-list-item> + @for (vs30 of form?.value?.vs30Multi; track vs30) { + <mat-list-item class="indent-list"> + {{ vs30 }} <sup> m</sup>/<sub>s</sub> </mat-list-item> } - + } @else { <mat-list-item> - <span class="parameter"> Z<sub>1.0</sub> </span>: - {{ form?.value?.z1p0 }} - @if (form?.value?.z1p0) { - <span> km</span> - } + <span class="parameter">Vs30</span>: {{ form?.value?.vs30 }} + <sup> m</sup>/<sub>s</sub> </mat-list-item> + } - <mat-list-item> - <span class="parameter"> Z<sub>2.5</sub> </span>: - {{ form?.value?.z2p5 }} - @if (form?.value?.z2p5) { - <span> km</span> - } - </mat-list-item> + <mat-list-item> + <span class="parameter"> Z<sub>1.0</sub> </span>: + {{ form?.value?.z1p0 }} + @if (form?.value?.z1p0) { + <span> km</span> + } + </mat-list-item> - <mat-list-item> - <span class="parameter"> Z<sub>SED</sub> </span>: - {{ form?.value?.zSed }} - @if (form?.value?.zSed) { - <span> km</span> - } - </mat-list-item> - </mat-list> - </div> + <mat-list-item> + <span class="parameter"> Z<sub>2.5</sub> </span>: + {{ form?.value?.z2p5 }} + @if (form?.value?.z2p5) { + <span> km</span> + } + </mat-list-item> + + <mat-list-item> + <span class="parameter"> Z<sub>SED</sub> </span>: + {{ form?.value?.zSed }} + @if (form?.value?.zSed) { + <span> km</span> + } + </mat-list-item> + </mat-list> </div> -} +</div> diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.spec.ts index d8af63c07b5ed14a5dbba0e247a2b3467c4cbddb..b8d5719b6ff3e200fa21333de58a54d2850d2f8d 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.spec.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.spec.ts @@ -1,5 +1,5 @@ +import {provideHttpClient} from '@angular/common/http'; import {ComponentFixture, TestBed} from '@angular/core/testing'; -import {provideMockStore} from '@ngrx/store/testing'; import {ParameterSummaryComponent} from './parameter-summary.component'; @@ -10,7 +10,7 @@ describe('ParameterSummaryComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [ParameterSummaryComponent], - providers: [provideMockStore({initialState: {}})], + providers: [provideHttpClient()], }).compileComponents(); }); diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.ts index 166e75ceceae0c498c77a8ad634b2e22b42325ea..ea07924b428e1863c7b6cdd4cf9d5a05fae85831 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.ts @@ -1,9 +1,7 @@ import {AsyncPipe} from '@angular/common'; -import {Component} from '@angular/core'; +import {Component, computed} from '@angular/core'; import {MatList, MatListItem} from '@angular/material/list'; -import {GmmFormControlIds, gmmUtils} from '@ghsc/nshmp-lib-ng/gmm'; -import {unbox} from 'ngrx-forms'; -import {map} from 'rxjs'; +import {GmmFormControlIds, gmmUtils} from '@ghsc/nshmp-lib-no-ngrx/gmm'; import {AppFacade} from '../../state/app.facade'; @@ -23,16 +21,12 @@ export class ParameterSummaryComponent { /** Function to convert IMT id to display */ imtIdToDisplay = gmmUtils.imtIdToDisplay; - /** ngrx-forms unbox function */ - unbox = unbox; /** Control form field state */ - form$ = this.facade.controlForm$; + form = this.facade.formGroup; /** List of GMMs */ - gmms$ = this.facade.usage$.pipe( - map(usage => usage?.response?.parameters?.gmm.values) - ); + gmms = computed(() => this.facade.usage()?.response?.parameters.gmm.values); constructor(private facade: AppFacade) {} } diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.html b/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.html index ca22b23d105a152befdc099d6e9597d043ee2f5a..b397645ef70dc9314de785f5ba03610739904e63 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.html +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.html @@ -1,26 +1,24 @@ -@if (form$ | async) { - <!-- Path Parameters --> - <div class="settings-subsection control-panel"> - <mat-label class="settings-subsection--label">Path Parameters</mat-label> - <!-- Event parameters: Distance input --> - <div class="settings-subsection--section distance-input"> - <mat-form-field class="grid-col-12"> - <mat-label>Distance (km)</mat-label> - <input - matInput - [max]="(parameters$ | async)?.distance?.max" - [min]="(parameters$ | async)?.distance?.min" - [ngrxFormControlState]="(controls$ | async)?.distance" - step="1" - type="number" - /> - <mat-error> - [ - {{ (parameters$ | async)?.distance?.min }}, - {{ (parameters$ | async)?.distance?.max }} - ] - </mat-error> - </mat-form-field> - </div> +<!-- Path Parameters --> +<div class="settings-subsection control-panel"> + <mat-label class="settings-subsection--label">Path Parameters</mat-label> + <!-- Event parameters: Distance input --> + <div class="settings-subsection--section distance-input"> + <mat-form-field class="grid-col-12"> + <mat-label>Distance (km)</mat-label> + <input + matInput + [max]="parameters()?.distance?.max" + [min]="parameters()?.distance?.min" + [formControl]="controls.distance" + step="1" + type="number" + /> + <mat-error> + [ + {{ parameters()?.distance?.min }}, + {{ parameters()?.distance?.max }} + ] + </mat-error> + </mat-form-field> </div> -} +</div> diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.spec.ts index 874eb64c82124cde0e87d45faeceb06c756c4d58..7a9ef8898e4616a208025c0a7b78750fdbdd1e7f 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.spec.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.spec.ts @@ -1,5 +1,6 @@ +import {provideHttpClient} from '@angular/common/http'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; -import {provideMockStore} from '@ngrx/store/testing'; +import {provideNoopAnimations} from '@angular/platform-browser/animations'; import {PathParametersComponent} from './path-parameters.component'; @@ -10,7 +11,7 @@ describe('PathParametersComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [PathParametersComponent], - providers: [provideMockStore({initialState: {}})], + providers: [provideHttpClient(), provideNoopAnimations()], teardown: {destroyAfterEach: false}, }).compileComponents(); })); diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.ts index 4608ac6235ac66079b0d68c2d3fb5a7f4188362c..1ca9f5cfd27f93367d1324bb5b8b8ecf4030745d 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.ts @@ -1,9 +1,8 @@ -import {AsyncPipe} from '@angular/common'; -import {Component} from '@angular/core'; +import {Component, computed, OnDestroy, OnInit} from '@angular/core'; +import {ReactiveFormsModule} from '@angular/forms'; import {MatError, MatFormField, MatLabel} from '@angular/material/form-field'; import {MatInput} from '@angular/material/input'; -import {NshmpNgrxFormsModule} from '@ghsc/nshmp-lib-ng/nshmp'; -import {map} from 'rxjs/operators'; +import {Subscription} from 'rxjs'; import {AppFacade} from '../../state/app.facade'; @@ -11,30 +10,33 @@ import {AppFacade} from '../../state/app.facade'; * Control panel form fields for GMM path parameters. */ @Component({ - imports: [ - MatLabel, - MatFormField, - MatInput, - MatError, - AsyncPipe, - NshmpNgrxFormsModule, - ], + imports: [MatLabel, MatFormField, MatInput, MatError, ReactiveFormsModule], selector: 'app-path-parameters', standalone: true, styleUrl: './path-parameters.component.scss', templateUrl: './path-parameters.component.html', }) -export class PathParametersComponent { +export class PathParametersComponent implements OnInit, OnDestroy { /** Form controls state */ - controls$ = this.facade.controlForm$.pipe(map(form => form?.controls)); + controls = this.facade.formGroup.controls; /** Control panel form field state */ - form$ = this.facade.controlForm$; + form = this.facade.formGroup; /** Usage parameters */ - parameters$ = this.facade.usage$.pipe( - map(usage => usage?.response?.parameters) - ); + parameters = computed(() => this.facade.usage()?.response.parameters); + + private distanceSubscription = new Subscription(); constructor(private facade: AppFacade) {} + + ngOnInit(): void { + this.distanceSubscription = this.controls.distance.valueChanges.subscribe( + () => this.facade.resetState() + ); + } + + ngOnDestroy(): void { + this.distanceSubscription.unsubscribe(); + } } diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.html b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.html index 82d44ff0709bf39249fc1ac1be72792be4b05911..a7d0427a776548881a2f0df780f2f0be1c27b75f 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.html +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.html @@ -1,27 +1,26 @@ <div class="height-full overflow-auto"> - @if (meanPlot$ | async) { - <nshmp-lib-ng-plot-settings - [plot]="meanPlot$ | async" + @if (meanPlot()) { + <nshmp-lib-no-ngrx-plot-settings + [plot]="meanPlot()" + (updatedPlot)="updatePlot(PlotIds.MEANS, $event)" class="mean-settings" /> } - @if (sigmaPlot$ | async) { - <nshmp-lib-ng-plot-settings - [plot]="sigmaPlot$ | async" + @if (sigmaPlot()) { + <nshmp-lib-no-ngrx-plot-settings + [plot]="sigmaPlot()" + (updatedPlot)="updatePlot(PlotIds.SIGMA, $event)" class="sigma-settings" /> } <div class="padding-y-2"></div> - <nshmp-lib-ng-plot-reset-plot-settings + <nshmp-lib-no-ngrx-plot-reset-plot-settings (resetClick)="facade.resetPlotSettings()" [resetDisabled]=" - (meanPlotSettings$ | async)?.isPristine && - (meanPlotSettings$ | async)?.isUntouched && - (sigmaPlotSettings$ | async)?.isPristine && - (sigmaPlotSettings$ | async)?.isPristine + meanPlotSettings().pristine && sigmaPlotSettings().pristine " /> </div> diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.spec.ts index 2d559563d711b2f8b34ab3202efbb2e9cc544a14..f32cb499109bcd69ddd134227f47a21b493974ff 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.spec.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.spec.ts @@ -1,6 +1,6 @@ import {provideHttpClient} from '@angular/common/http'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; -import {provideMockStore} from '@ngrx/store/testing'; +import {provideNoopAnimations} from '@angular/platform-browser/animations'; import {PlotsSettingsComponent} from './plots-settings.component'; @@ -11,7 +11,7 @@ describe('PlotsSettingsComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [PlotsSettingsComponent], - providers: [provideMockStore({initialState: {}}), provideHttpClient()], + providers: [provideHttpClient(), provideNoopAnimations()], teardown: {destroyAfterEach: false}, }).compileComponents(); })); diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.ts index 483f71ff8d498a43f6cc19719beac385400ba3df..3e6c0e88dab3cec56d839e6b05f176df8ae579a3 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.ts @@ -1,10 +1,11 @@ import {AsyncPipe} from '@angular/common'; -import {Component} from '@angular/core'; +import {Component, computed} from '@angular/core'; +import {gmmUtils} from '@ghsc/nshmp-lib-no-ngrx/gmm'; import { NshmpLibNgPlotResetPlotSettingsComponent, NshmpLibNgPlotSettingsComponent, -} from '@ghsc/nshmp-lib-ng/plot'; -import {map} from 'rxjs/operators'; + NshmpPlot, +} from '@ghsc/nshmp-lib-no-ngrx/plot'; import {AppFacade} from '../../state/app.facade'; @@ -23,19 +24,27 @@ import {AppFacade} from '../../state/app.facade'; templateUrl: './plots-settings.component.html', }) export class PlotsSettingsComponent { + PlotIds = gmmUtils.PlotType; + /** Mean plot state */ - meanPlot$ = this.facade.meanPlotState$; + meanPlot = this.facade.meanPlotState; + /** Mean plot settings */ - meanPlotSettings$ = this.facade.meanPlotState$.pipe( - map(plot => plot.settingsForm) - ); + meanPlotSettings = computed(() => this.facade.meanPlotState().settingsForm); /** Sigma plot state */ - sigmaPlot$ = this.facade.sigmaPlotState$; + sigmaPlot = this.facade.sigmaPlotState; + /** Sigma plot settings */ - sigmaPlotSettings$ = this.facade.sigmaPlotState$.pipe( - map(plot => plot.settingsForm) - ); + sigmaPlotSettings = computed(() => this.facade.sigmaPlotState().settingsForm); constructor(public facade: AppFacade) {} + + updatePlot(id: string, plot: NshmpPlot): void { + const plots = new Map(this.facade.state().plots); + plots.set(id, plot); + this.facade.updateState({ + plots, + }); + } } diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.html b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.html index a18cbd37e9a366a325a41d0d9464c4f1e6e9d0cd..dac5eeac17ff78a30a11412a67f7b5235cc163f5 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.html +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.html @@ -1,4 +1,4 @@ -<nshmp-lib-ng-plots-container> +<nshmp-lib-no-ngrx-plots-container> <mat-accordion multi> <!-- GMM vs. magnitude plot --> <mat-expansion-panel expanded> @@ -8,8 +8,8 @@ <mat-divider /> - @if (meanPlotData$ | async; as meanPlot) { - <nshmp-lib-ng-plot class="mean-plot" [plot]="meanPlot" /> + @if (meanPlotData()) { + <nshmp-lib-no-ngrx-plot class="mean-plot" [plot]="meanPlotData()" /> } </mat-expansion-panel> @@ -21,8 +21,8 @@ <mat-divider /> - @if (sigmaPlotData$ | async; as sigmaPlot) { - <nshmp-lib-ng-plot class="sigma-plot" [plot]="sigmaPlot" /> + @if (sigmaPlotData()) { + <nshmp-lib-no-ngrx-plot class="sigma-plot" [plot]="sigmaPlotData()" /> } </mat-expansion-panel> @@ -43,7 +43,7 @@ </mat-expansion-panel-header> <mat-divider /> - <nshmp-lib-ng-app-metadata [repositories]="repositories$ | async" /> + <nshmp-lib-no-ngrx-app-metadata [repositories]="repositories()" /> </mat-expansion-panel> </mat-accordion> -</nshmp-lib-ng-plots-container> +</nshmp-lib-no-ngrx-plots-container> diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.spec.ts index 611faa48c7030c6b191cef494fb6f9d4cf68a2be..12310e664cae4389f25ed6e690712a017a78e588 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.spec.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.spec.ts @@ -1,7 +1,6 @@ import {provideHttpClient} from '@angular/common/http'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; import {provideNoopAnimations} from '@angular/platform-browser/animations'; -import {provideMockStore} from '@ngrx/store/testing'; import {PlotsComponent} from './plots.component'; @@ -12,11 +11,7 @@ describe('PlotsComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [PlotsComponent], - providers: [ - provideMockStore({initialState: {}}), - provideHttpClient(), - provideNoopAnimations(), - ], + providers: [provideHttpClient(), provideNoopAnimations()], teardown: {destroyAfterEach: false}, }).compileComponents(); })); diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.ts index 7800906fbbd0c73035cb8254f874d92377559c42..8088793cdbb287844f31bf1e7c411aadc354e93d 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.ts @@ -1,5 +1,5 @@ import {AsyncPipe} from '@angular/common'; -import {Component} from '@angular/core'; +import {Component, computed} from '@angular/core'; import {MatDivider} from '@angular/material/divider'; import { MatAccordion, @@ -7,12 +7,11 @@ import { MatExpansionPanelHeader, MatExpansionPanelTitle, } from '@angular/material/expansion'; -import {NshmpLibNgAppMetadataComponent} from '@ghsc/nshmp-lib-ng/nshmp'; +import {NshmpLibNgAppMetadataComponent} from '@ghsc/nshmp-lib-no-ngrx/nshmp'; import { NshmpLibNgPlotComponent, NshmpLibNgPlotsContainerComponent, -} from '@ghsc/nshmp-lib-ng/plot'; -import {map} from 'rxjs/operators'; +} from '@ghsc/nshmp-lib-no-ngrx/plot'; import {AppFacade} from '../../state/app.facade'; import {ParameterSummaryComponent} from '../parameter-summary/parameter-summary.component'; @@ -40,15 +39,13 @@ import {ParameterSummaryComponent} from '../parameter-summary/parameter-summary. }) export class PlotsComponent { /** Mean plot data */ - meanPlotData$ = this.facade.meanPlotState$.pipe(map(plot => plot.plotData)); + meanPlotData = computed(() => this.facade.meanPlotState().plotData); /** Sigma plot data */ - sigmaPlotData$ = this.facade.sigmaPlotState$.pipe(map(plot => plot.plotData)); + sigmaPlotData = computed(() => this.facade.sigmaPlotState().plotData); /** Repo metadata */ - repositories$ = this.facade.usage$.pipe( - map(usage => usage?.metadata.repositories) - ); + repositories = computed(() => this.facade.usage()?.metadata.repositories); constructor(private facade: AppFacade) {} } diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.html b/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.html index 782f79c8b99c07894cfa9596fee933828e0140be..6389406f39813c3b775970ac2b124970011e72d4 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.html +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.html @@ -1,77 +1,75 @@ -@if (form$ | async) { - <!-- Site & Basin--> - <div class="settings-subsection control-panel"> - <mat-label class="settings-subsection--label">Site & Basin</mat-label> +<!-- Site & Basin--> +<div class="settings-subsection control-panel"> + <mat-label class="settings-subsection--label">Site & Basin</mat-label> - <div class="settings-subsection--section grid-row grid-gap-sm"> - <!-- Site & Basin: Vs30 input --> - <nshmp-lib-ng-gmm-multi-select - class="grid-col-12 vs30-input" - label="V<sub>s30</sub> (<sup>m</sup>/<sub>s</sub>)" - [multiple]="vs30Multiple$ | async" - [numberControl]="(controls$ | async)?.vs30" - [parameter]="(parameters$ | async)?.vs30" - placeholder="Select values..." - [selectControl]="(controls$ | async)?.vs30Multi" - [selectOptions]="vs30CommonValues" - /> + <div class="settings-subsection--section grid-row grid-gap-sm"> + <!-- Site & Basin: Vs30 input --> + <nshmp-lib-no-ngrx-gmm-multi-select + class="grid-col-12 vs30-input" + label="V<sub>s30</sub> (<sup>m</sup>/<sub>s</sub>)" + [multiple]="vs30Multiple$ | async" + [numberControl]="controls?.vs30" + [parameter]="parameters()?.vs30" + placeholder="Select values..." + [selectControl]="controls.vs30Multi" + [selectOptions]="vs30CommonValues" + /> - <!-- Site & Basin: Z 1.0 input --> - <mat-form-field class="grid-col-4 z1p0-input"> - <mat-label>Z<sub>1.0</sub> (km)</mat-label> - <input - matInput - [max]="(parameters$ | async)?.z1p0?.max" - [min]="(parameters$ | async)?.z1p0?.min" - [ngrxFormControlState]="(controls$ | async)?.z1p0" - step="1.0" - type="number" - /> - <mat-error> - [ - {{ (parameters$ | async)?.z1p0?.min }}, - {{ (parameters$ | async)?.z1p0?.max }} - ] - </mat-error> - </mat-form-field> + <!-- Site & Basin: Z 1.0 input --> + <mat-form-field class="grid-col-4 z1p0-input"> + <mat-label>Z<sub>1.0</sub> (km)</mat-label> + <input + matInput + [max]="parameters()?.z1p0?.max" + [min]="parameters()?.z1p0?.min" + [formControl]="controls.z1p0" + step="1.0" + type="number" + /> + <mat-error> + [ + {{ parameters()?.z1p0?.min }}, + {{ parameters()?.z1p0?.max }} + ] + </mat-error> + </mat-form-field> - <!-- Site & Basin: Z 2.5 input --> - <mat-form-field class="grid-col-4 z2p5-input"> - <mat-label>Z<sub>2.5</sub> (km)</mat-label> - <input - matInput - [max]="(parameters$ | async)?.z2p5?.max" - [min]="(parameters$ | async)?.z2p5?.min" - [ngrxFormControlState]="(controls$ | async)?.z2p5" - step="1.0" - type="number" - /> - <mat-error> - [ - {{ (parameters$ | async)?.z2p5?.min }}, - {{ (parameters$ | async)?.z2p5?.max }} - ] - </mat-error> - </mat-form-field> + <!-- Site & Basin: Z 2.5 input --> + <mat-form-field class="grid-col-4 z2p5-input"> + <mat-label>Z<sub>2.5</sub> (km)</mat-label> + <input + matInput + [max]="parameters()?.z2p5?.max" + [min]="parameters()?.z2p5?.min" + [formControl]="controls?.z2p5" + step="1.0" + type="number" + /> + <mat-error> + [ + {{ parameters()?.z2p5?.min }}, + {{ parameters()?.z2p5?.max }} + ] + </mat-error> + </mat-form-field> - <!-- Site & Basin: zSed input --> - <mat-form-field class="grid-col-4 zsed-input"> - <mat-label>Z<sub>SED</sub> (km)</mat-label> - <input - matInput - [max]="(parameters$ | async)?.zSed?.max" - [min]="(parameters$ | async)?.zSed?.min" - [ngrxFormControlState]="(controls$ | async)?.zSed" - step="1.0" - type="number" - /> - <mat-error> - [ - {{ (parameters$ | async)?.zSed?.min }}, - {{ (parameters$ | async)?.zSed?.max }} - ] - </mat-error> - </mat-form-field> - </div> + <!-- Site & Basin: zSed input --> + <mat-form-field class="grid-col-4 zsed-input"> + <mat-label>Z<sub>SED</sub> (km)</mat-label> + <input + matInput + [max]="parameters()?.zSed?.max" + [min]="parameters()?.zSed?.min" + [formControl]="controls.zSed" + step="1.0" + type="number" + /> + <mat-error> + [ + {{ parameters()?.zSed?.min }}, + {{ parameters()?.zSed?.max }} + ] + </mat-error> + </mat-form-field> </div> -} +</div> diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.spec.ts index b7857664be688118f1bb5b350b8121ab47340f6c..e6ed2c402ac46bc7ed17e1650a6ffa423c4b635d 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.spec.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.spec.ts @@ -1,5 +1,6 @@ +import {provideHttpClient} from '@angular/common/http'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; -import {provideMockStore} from '@ngrx/store/testing'; +import {provideNoopAnimations} from '@angular/platform-browser/animations'; import {SiteParametersComponent} from './site-parameters.component'; @@ -10,7 +11,7 @@ describe('SiteParametersComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [SiteParametersComponent], - providers: [provideMockStore({initialState: {}})], + providers: [provideHttpClient(), provideNoopAnimations()], teardown: {destroyAfterEach: false}, }).compileComponents(); })); diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.ts index f71aeb052dd64d16982788beecf487002a972ada..bc789827acc0462dba39e2f6451d85cbc873fcbd 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.ts @@ -1,13 +1,14 @@ import {AsyncPipe} from '@angular/common'; -import {Component} from '@angular/core'; +import {Component, computed, OnDestroy, OnInit} from '@angular/core'; +import {ReactiveFormsModule} from '@angular/forms'; import {MatError, MatFormField, MatLabel} from '@angular/material/form-field'; import {MatInput} from '@angular/material/input'; import { GmmFormControlIds, NshmpLibNgGmmMultiSelectComponent, VS30_COMMON_VALUES, -} from '@ghsc/nshmp-lib-ng/gmm'; -import {NshmpNgrxFormsModule} from '@ghsc/nshmp-lib-ng/nshmp'; +} from '@ghsc/nshmp-lib-no-ngrx/gmm'; +import {combineLatest, Subscription} from 'rxjs'; import {map} from 'rxjs/operators'; import {AppFacade} from '../../state/app.facade'; @@ -23,36 +24,49 @@ import {AppFacade} from '../../state/app.facade'; MatInput, MatError, AsyncPipe, - NshmpNgrxFormsModule, + ReactiveFormsModule, ], selector: 'app-site-parameters', standalone: true, styleUrl: './site-parameters.component.scss', templateUrl: './site-parameters.component.html', }) -export class SiteParametersComponent { +export class SiteParametersComponent implements OnInit, OnDestroy { /** Common vs30 values */ vs30CommonValues = VS30_COMMON_VALUES; /** Form controls state */ - controls$ = this.facade.controlForm$.pipe(map(form => form?.controls)); + controls = this.facade.formGroup.controls; /** Control panel form field state */ - form$ = this.facade.controlForm$; + form = this.facade.formGroup; /** Usage parameters */ - parameters$ = this.facade.usage$.pipe( - map(usage => usage?.response?.parameters) - ); + parameters = computed(() => this.facade.usage()?.response.parameters); - /** Whether vs30 is multi-selectable */ - vs30Multiple$ = this.controls$.pipe( + /** Whether Vs30 is multi-selectable */ + vs30Multiple$ = this.controls.multiSelectableParam.valueChanges.pipe( map( - controls => - controls.multiSelectableParam.value === - GmmFormControlIds.VS30.toString() + multiSelectableParam => + multiSelectableParam.toString() === GmmFormControlIds.VS30.toString() ) ); + private valueSubscription = new Subscription(); + constructor(private facade: AppFacade) {} + + ngOnInit(): void { + combineLatest([ + this.controls.vs30Multi.valueChanges, + this.controls.vs30.valueChanges, + this.controls.z1p0.valueChanges, + this.controls.z2p5.valueChanges, + this.controls.zSed.valueChanges, + ]).subscribe(() => this.facade.resetState()); + } + + ngOnDestroy(): void { + this.valueSubscription.unsubscribe(); + } } diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.html b/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.html index d767694472687cb9f8d06c650f6c964714ed1ec6..b391b897e4ce79eac16cedb33bfa2bf4b7cec663 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.html +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.html @@ -1,65 +1,63 @@ -@if (form$ | async) { - <!-- Source Parameters --> - <div class="settings-subsection control-panel"> - <mat-label class="settings-subsection--label">Source Geometry</mat-label> +<!-- Source Parameters --> +<div class="settings-subsection control-panel"> + <mat-label class="settings-subsection--label">Source Geometry</mat-label> - <div class="settings-subsection--section grid-row grid-gap-sm"> - <!-- Source Parameters: zTor input --> - <mat-form-field class="grid-col-4 ztor-input"> - <mat-label>Z<sub>TOR</sub> (km)</mat-label> - <input - matInput - [max]="(parameters$ | async)?.zTor?.max" - [min]="(parameters$ | async)?.zTor?.min" - [ngrxFormControlState]="(controls$ | async)?.zTor" - step="0.5" - type="number" - /> - <mat-error> - [ - {{ (parameters$ | async)?.zTor?.min }}, - {{ (parameters$ | async)?.zTor?.max }} - ] - </mat-error> - </mat-form-field> + <div class="settings-subsection--section grid-row grid-gap-sm"> + <!-- Source Parameters: zTor input --> + <mat-form-field class="grid-col-4 ztor-input"> + <mat-label>Z<sub>TOR</sub> (km)</mat-label> + <input + matInput + [max]="parameters()?.zTor?.max" + [min]="parameters()?.zTor?.min" + [formControl]="controls.zTor" + step="0.5" + type="number" + /> + <mat-error> + [ + {{ parameters()?.zTor?.min }}, + {{ parameters()?.zTor?.max }} + ] + </mat-error> + </mat-form-field> - <!-- Source Parameters: Dip input --> - <mat-form-field class="grid-col-4 dip-input"> - <mat-label>Dip (°)</mat-label> - <input - matInput - [max]="(parameters$ | async)?.dip?.max" - [min]="(parameters$ | async)?.dip?.min" - [ngrxFormControlState]="(controls$ | async)?.dip" - step="5" - type="number" - /> - <mat-error> - [ - {{ (parameters$ | async)?.dip?.min }}, - {{ (parameters$ | async)?.dip?.max }} - ] - </mat-error> - </mat-form-field> + <!-- Source Parameters: Dip input --> + <mat-form-field class="grid-col-4 dip-input"> + <mat-label>Dip (°)</mat-label> + <input + matInput + [max]="parameters()?.dip?.max" + [min]="parameters()?.dip?.min" + [formControl]="controls.dip" + step="5" + type="number" + /> + <mat-error> + [ + {{ parameters()?.dip?.min }}, + {{ parameters()?.dip?.max }} + ] + </mat-error> + </mat-form-field> - <!-- Source Parameters: Width input --> - <mat-form-field class="grid-col-4 width-input"> - <mat-label>Width (km)</mat-label> - <input - matInput - [max]="(parameters$ | async)?.width?.max" - [min]="(parameters$ | async)?.width?.min" - [ngrxFormControlState]="(controls$ | async)?.width" - step="1" - type="number" - /> - <mat-error> - [ - {{ (parameters$ | async)?.width?.min }}, - {{ (parameters$ | async)?.width?.max }} - ] - </mat-error> - </mat-form-field> - </div> + <!-- Source Parameters: Width input --> + <mat-form-field class="grid-col-4 width-input"> + <mat-label>Width (km)</mat-label> + <input + matInput + [max]="parameters()?.width?.max" + [min]="parameters()?.width?.min" + [formControl]="controls.width" + step="1" + type="number" + /> + <mat-error> + [ + {{ parameters()?.width?.min }}, + {{ parameters()?.width?.max }} + ] + </mat-error> + </mat-form-field> </div> -} +</div> diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.spec.ts index a3e89bc207355e1bd993b467882611c74970cacd..a2e4133e63cdba16d3520d9dd1cbfff868290f23 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.spec.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.spec.ts @@ -1,5 +1,6 @@ +import {provideHttpClient} from '@angular/common/http'; import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; -import {provideMockStore} from '@ngrx/store/testing'; +import {provideNoopAnimations} from '@angular/platform-browser/animations'; import {SourceParametersComponent} from './source-parameters.component'; @@ -10,7 +11,7 @@ describe('SourceParametersComponent', () => { beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ imports: [SourceParametersComponent], - providers: [provideMockStore({initialState: {}})], + providers: [provideHttpClient(), provideNoopAnimations()], teardown: {destroyAfterEach: false}, }).compileComponents(); })); diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.ts index 4a4c59310d766e4d773efd8a389085b842d7e310..8ce5cdeadaecc5702046f6e4c87cf416946558f5 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.ts @@ -1,9 +1,9 @@ import {AsyncPipe} from '@angular/common'; -import {Component} from '@angular/core'; +import {Component, computed, OnDestroy, OnInit} from '@angular/core'; +import {ReactiveFormsModule} from '@angular/forms'; import {MatError, MatFormField, MatLabel} from '@angular/material/form-field'; import {MatInput} from '@angular/material/input'; -import {NshmpNgrxFormsModule} from '@ghsc/nshmp-lib-ng/nshmp'; -import {map} from 'rxjs/operators'; +import {combineLatest, Subscription} from 'rxjs'; import {AppFacade} from '../../state/app.facade'; @@ -17,24 +17,36 @@ import {AppFacade} from '../../state/app.facade'; MatInput, MatError, AsyncPipe, - NshmpNgrxFormsModule, + ReactiveFormsModule, ], selector: 'app-source-parameters', standalone: true, styleUrl: './source-parameters.component.scss', templateUrl: './source-parameters.component.html', }) -export class SourceParametersComponent { +export class SourceParametersComponent implements OnInit, OnDestroy { /** Form controls state */ - controls$ = this.facade.controlForm$.pipe(map(form => form?.controls)); + controls = this.facade.formGroup.controls; /** Control panel form field state */ - form$ = this.facade.controlForm$; + form = this.facade.formGroup; /** Usage parameters */ - parameters$ = this.facade.usage$.pipe( - map(usage => usage?.response?.parameters) - ); + parameters = computed(() => this.facade.usage()?.response.parameters); + + private valueSubscription = new Subscription(); constructor(private facade: AppFacade) {} + + ngOnInit(): void { + combineLatest([ + this.controls.dip.valueChanges, + this.controls.width.valueChanges, + this.controls.zTor.valueChanges, + ]).subscribe(() => this.facade.resetState()); + } + + ngOnDestroy(): void { + this.valueSubscription.unsubscribe(); + } } diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/models/gmm-magnitude-form-controls.model.ts b/projects/nshmp-apps/src/app/gmm/magnitude/models/gmm-magnitude-form-controls.model.ts index ea75d6a0f7c73c73ba92a7c4147cb65d4da1e77b..2d1c266e740de116767d97028e18b93b38d75666 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/models/gmm-magnitude-form-controls.model.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/models/gmm-magnitude-form-controls.model.ts @@ -1,4 +1,7 @@ -import {GmmFormControlIds, GmmImtFormControls} from '@ghsc/nshmp-lib-ng/gmm'; +import { + GmmFormControlIds, + GmmImtFormControls, +} from '@ghsc/nshmp-lib-no-ngrx/gmm'; /** * Control panel form fields. diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/state/app.actions.ts b/projects/nshmp-apps/src/app/gmm/magnitude/state/app.actions.ts deleted file mode 100644 index 26382a0d252a3e5f5ba35c4996c5580c998929bd..0000000000000000000000000000000000000000 --- a/projects/nshmp-apps/src/app/gmm/magnitude/state/app.actions.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { - GmmMagnitudeResponse, - GmmMagnitudeUsage, -} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws/gmm-services'; -import {createActionGroup, emptyProps, props} from '@ngrx/store'; -import {sharedActions} from 'projects/nshmp-apps/src/shared/state/shared'; - -/** - * GMM vs magnitude NGRX actions. - */ -export const actions = createActionGroup({ - events: { - ...sharedActions, - /** Action to set the initial form values from query or default */ - 'Initial Form Set': emptyProps(), - /** Service response action */ - 'Service Response': props<{serviceResponses: GmmMagnitudeResponse[]}>(), - /** Usage response action */ - 'Usage Response': props<{usageResponses: GmmMagnitudeUsage}>(), - }, - source: 'GMM vs Magnitude', -}); diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/state/app.effects.ts b/projects/nshmp-apps/src/app/gmm/magnitude/state/app.effects.ts deleted file mode 100644 index a45bc5824bb9371129e31ebe3fac7e6ba1ae5f13..0000000000000000000000000000000000000000 --- a/projects/nshmp-apps/src/app/gmm/magnitude/state/app.effects.ts +++ /dev/null @@ -1,147 +0,0 @@ -import {Injectable} from '@angular/core'; -import {gmmUtils} from '@ghsc/nshmp-lib-ng/gmm'; -import {NshmpService, SpinnerService} from '@ghsc/nshmp-lib-ng/nshmp'; -import {plotUtils} from '@ghsc/nshmp-lib-ng/plot'; -import { - GmmMagnitudeResponse, - GmmMagnitudeUsage, -} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws/gmm-services'; -import {Actions, createEffect, ofType} from '@ngrx/effects'; -import {concatLatestFrom} from '@ngrx/operators'; -import {Store} from '@ngrx/store'; -import {environment} from 'projects/nshmp-apps/src/environments/environment'; -import {catchError, exhaustMap, map, mergeMap} from 'rxjs/operators'; - -import {defaultFormValues} from '../utils/app.default-values'; -import {serviceResponseToPlotData} from '../utils/response.handler'; -import {actions} from './app.actions'; -import {AppFacade} from './app.facade'; -import {magnitudeAppFeature} from './app.reducer'; - -/** - * NGRX application effects. - */ -@Injectable() -export class MagnitudeAppEffects { - /** nshmp-ws base URL */ - baseUrl = environment.webServices.data.url; - /** GMM service URL */ - serviceUrl = `${this.baseUrl}${environment.webServices.data.services.gmmMagnitude}`; - - /** - * Call the services. - */ - callService$ = createEffect(() => - this.actions$.pipe( - ofType(actions.callServices), - concatLatestFrom(() => - this.store.select(magnitudeAppFeature.selectGmmMagnitudeAppState) - ), - exhaustMap(([, state]) => { - this.spinnerService.show(SpinnerService.MESSAGE_SERVICE); - - const urls = gmmUtils.serviceEndpoints( - this.serviceUrl, - state.controlForm.value, - state.controlForm.value.multiSelectableParam - ); - - return this.nshmpService.callServices$(urls).pipe( - mergeMap((serviceResponses: GmmMagnitudeResponse[]) => { - return [actions.serviceResponse({serviceResponses})]; - }), - catchError((error: Error) => this.nshmpService.throwError$(error)) - ); - }), - catchError((error: Error) => this.nshmpService.throwError$(error)) - ) - ); - - /** - * Transform the service responses to plot data. - */ - createData$ = createEffect(() => - this.actions$.pipe( - ofType(actions.serviceResponse), - concatLatestFrom(() => - this.store.select(magnitudeAppFeature.selectGmmMagnitudeAppState) - ), - map(([, state]) => { - const plots = plotUtils.updateAppPlotSettings( - serviceResponseToPlotData(state) - ); - this.spinnerService.remove(); - return actions.plots({plots}); - }), - catchError((error: Error) => this.nshmpService.throwError$(error)) - ) - ); - - /** - * Initialize the application. - */ - init$ = createEffect(() => - this.actions$.pipe( - ofType(actions.init), - concatLatestFrom(() => - this.store.select(magnitudeAppFeature.selectControlForm) - ), - exhaustMap(([, form]) => { - this.spinnerService.show(SpinnerService.MESSAGE_METADATA); - return this.nshmpService - .callService$<GmmMagnitudeUsage>(this.serviceUrl) - .pipe( - mergeMap(usage => { - const parameters = usage.response.parameters; - const controls = form.controls; - const values = defaultFormValues(parameters); - - const typedActions = gmmUtils.initialFormSetActions( - form, - values, - parameters - ); - typedActions.push(actions.usageResponse({usageResponses: usage})); - gmmUtils.addFormAction( - parameters.distance, - controls.distance.id, - values.distance, - typedActions - ); - gmmUtils.addFormAction( - parameters.mMax, - controls.mMax.id, - values.mMax, - typedActions - ); - gmmUtils.addFormAction( - parameters.mMin, - controls.mMin.id, - values.mMin, - typedActions - ); - gmmUtils.addFormAction( - parameters.step, - controls.step.id, - values.step, - typedActions - ); - - this.spinnerService.remove(); - return typedActions; - }), - catchError((error: Error) => this.nshmpService.throwError$(error)) - ); - }), - catchError((error: Error) => this.nshmpService.throwError$(error)) - ) - ); - - constructor( - private actions$: Actions, - private facade: AppFacade, - private nshmpService: NshmpService, - private spinnerService: SpinnerService, - private store: Store - ) {} -} diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/state/app.facade.ts b/projects/nshmp-apps/src/app/gmm/magnitude/state/app.facade.ts index 0e09fe9ab9909d954da32b3d527aafc037d8baec..28c3ff154c3c57dbd2799cb87b03f3e4f9207d80 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/state/app.facade.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/state/app.facade.ts @@ -1,19 +1,33 @@ -import {Injectable} from '@angular/core'; -import {ServiceCallInfo} from '@ghsc/nshmp-lib-ng/nshmp'; -import {NshmpPlot} from '@ghsc/nshmp-lib-ng/plot'; +import {computed, Injectable, Signal, signal} from '@angular/core'; +import {AbstractControl, FormBuilder, Validators} from '@angular/forms'; +import {gmmUtils} from '@ghsc/nshmp-lib-no-ngrx/gmm'; +import { + FormGroupControls, + NshmpService, + ServiceCallInfo, + SpinnerService, +} from '@ghsc/nshmp-lib-no-ngrx/nshmp'; +import {NshmpPlot} from '@ghsc/nshmp-lib-no-ngrx/plot'; import { GmmMagnitudeResponse, GmmMagnitudeUsage, } from '@ghsc/nshmp-utils-ts/libs/nshmp-ws/gmm-services'; import {EnumParameterValues} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws-utils/metadata'; -import {select, Store} from '@ngrx/store'; -import {FormGroupState} from 'ngrx-forms'; import {environment} from 'projects/nshmp-apps/src/environments/environment'; -import {Observable} from 'rxjs'; +import { + redrawPlots, + resetPlotSettings, +} from 'projects/nshmp-apps/src/shared/utils/facade.utils'; +import {catchError} from 'rxjs'; import {GmmMagnitudeFormControls} from '../models/gmm-magnitude-form-controls.model'; -import {actions} from './app.actions'; -import {magnitudeAppFeature} from './app.reducer'; +import { + DEFAULT_FORM_VALUES, + defaultPlots, + usageFormValues, +} from '../utils/app.default-values'; +import {serviceResponseToPlotData} from '../utils/response.handler'; +import {AppState, INITIAL_STATE} from './app.state'; /** * Entrypoint to NGRX store for GM vs magnitude application. @@ -27,89 +41,242 @@ export class AppFacade { /** GMM service URL */ serviceUrl = `${this.baseUrl}${environment.webServices.data.services.gmmMagnitude}`; - constructor(private store: Store) {} + readonly formGroup = this.formBuilder.group({ + ...DEFAULT_FORM_VALUES, + gmmSource: [], + MwMulti: [], + vs30Multi: [], + }) as FormGroupControls<GmmMagnitudeFormControls>; - /** - * Returns the control panel form. - */ - get controlForm$(): Observable<FormGroupState<GmmMagnitudeFormControls>> { - return this.store.pipe(select(magnitudeAppFeature.selectControlForm)); + readonly state = signal<AppState>(INITIAL_STATE); + + constructor( + private formBuilder: FormBuilder, + private nshmpService: NshmpService, + private spinnerService: SpinnerService + ) { + this.addValidators(this.formGroup); + this.formGroup.controls.gmmSource.setValue([]); + this.formGroup.controls.showEpistemicUncertainty.disable(); } /** * Returns the mean plot state. */ - get meanPlotState$(): Observable<NshmpPlot> { - return this.store.pipe(select(magnitudeAppFeature.selectMeanPlot)); + get meanPlotState(): Signal<NshmpPlot> { + return computed(() => this.state().plots?.get(gmmUtils.PlotType.MEANS)); } /** * Returns service call info observable. */ - get serviceCallInfo$(): Observable<ServiceCallInfo> { - return this.store.pipe(select(magnitudeAppFeature.selectServiceCallInfo)); + get serviceCallInfo(): Signal<ServiceCallInfo> { + return computed(() => this.state().serviceCallInfo); } /** * Returns the Gmm distance service responses. */ - get serviceResponse$(): Observable<GmmMagnitudeResponse[]> { - return this.store.pipe(select(magnitudeAppFeature.selectServiceResponses)); + get serviceResponse(): Signal<GmmMagnitudeResponse[]> { + return computed(() => this.state().serviceResponses); } /** * Returns the mean plot state. */ - get sigmaPlotState$(): Observable<NshmpPlot> { - return this.store.pipe(select(magnitudeAppFeature.selectSigmaPlot)); + get sigmaPlotState(): Signal<NshmpPlot> { + return computed(() => this.state().plots?.get(gmmUtils.PlotType.SIGMA)); } /** * Returns supported IMTs observable. */ - get supportedImts$(): Observable<EnumParameterValues[]> { - return this.store.pipe(select(magnitudeAppFeature.selectSupportedImts)); + get supportedImts(): Signal<EnumParameterValues[]> { + return computed(() => this.state().supportedImts); } /** * Returns the Gmm distance usage response. */ - get usage$(): Observable<GmmMagnitudeUsage> { - return this.store.pipe(select(magnitudeAppFeature.selectUsageResponses)); + get usage(): Signal<GmmMagnitudeUsage> { + return computed(() => this.state().usageResponse); } /** * Calls the Gmm distance service. */ callService(): void { - this.store.dispatch(actions.callServices()); + if (this.formGroup.invalid) { + return; + } + + this.spinnerService.show(SpinnerService.MESSAGE_SERVICE); + + const urls = gmmUtils.serviceEndpoints( + this.serviceUrl, + this.formGroup.getRawValue(), + this.formGroup.getRawValue().multiSelectableParam + ); + + this.nshmpService + .callServices$<GmmMagnitudeResponse>(urls) + .pipe(catchError((error: Error) => this.nshmpService.throwError$(error))) + .subscribe(serviceResponses => + this.handleServiceResponses(serviceResponses) + ); + } + + /** + * Create plots based on current state and form group. + */ + createPlots(): void { + this.updateState({ + plots: serviceResponseToPlotData(this.state(), this.formGroup), + }); } /** * Initialize the application. */ init(): void { - this.store.dispatch(actions.init()); + this.spinnerService.show(SpinnerService.MESSAGE_METADATA); + + this.nshmpService + .callService$<GmmMagnitudeUsage>(this.serviceUrl) + .pipe(catchError((error: Error) => this.nshmpService.throwError$(error))) + .subscribe(usageResponse => this.handleUsageResponse(usageResponse)); } /** * Redraw the plot. */ plotRedraw(): void { - this.store.dispatch(actions.plotRedraw()); + this.updateState({ + plots: redrawPlots(this.state().plots), + }); } /** * Reset the control panel. */ resetControlPanel(): void { - this.store.dispatch(actions.resetControlPanel()); + this.formGroup.reset( + usageFormValues(this.state().usageResponse.response.parameters) + ); } /** * Reset the plot settings. */ resetPlotSettings(): void { - this.store.dispatch(actions.resetSettings()); + resetPlotSettings({ + currentPlots: this.state().plots, + defaultPlots: defaultPlots(), + }); + } + + /** + * Reset the state. + */ + resetState(): void { + const serviceCallInfo = gmmUtils.serviceCallInfo({ + multiSelectableParam: this.formGroup.getRawValue().multiSelectableParam, + serviceName: this.state().serviceCallInfo.serviceName, + serviceResponses: this.state().serviceResponses, + serviceUrl: this.serviceUrl, + values: this.formGroup.getRawValue(), + }); + + this.updateState({ + serviceCallInfo, + serviceResponses: null, + }); + + this.createPlots(); + } + + /** + * Update state. + * + * @param state Partial new state to update + */ + updateState(state: Partial<AppState>): void { + this.state.set({ + ...this.state(), + ...state, + }); + } + + /** + * Add validators to form controls. + * + * @param form The form group + */ + private addValidators( + form: FormGroupControls<GmmMagnitudeFormControls> + ): void { + const required = (control: AbstractControl) => Validators.required(control); + + form.controls.Mw.addValidators(required); + form.controls.dip.addValidators(required); + form.controls.gmmSource.addValidators(required); + form.controls.imt.addValidators(required); + form.controls.multiSelectableParam.addValidators(required); + form.controls.vs30.addValidators(required); + form.controls.width.addValidators(required); + form.controls.zTor.addValidators(required); + + form.updateValueAndValidity(); + } + + private handleServiceResponses( + serviceResponses: GmmMagnitudeResponse[] + ): void { + const means = serviceResponses.map(s => s.response.means); + const sigmas = serviceResponses.map(s => s.response.sigmas); + const hasLogicTree = gmmUtils.hasTree([...means, ...sigmas]); + + if (hasLogicTree) { + this.formGroup.controls.showEpistemicUncertainty.enable(); + } else { + this.formGroup.controls.showEpistemicUncertainty.disable(); + } + + this.updateState({ + serviceCallInfo: gmmUtils.serviceCallInfo({ + multiSelectableParam: this.formGroup.getRawValue().multiSelectableParam, + serviceName: this.state().serviceCallInfo.serviceName, + serviceResponses, + serviceUrl: this.serviceUrl, + values: this.formGroup.getRawValue(), + }), + serviceResponses, + }); + + this.createPlots(); + + this.spinnerService.remove(); + } + + private handleUsageResponse(usageResponse: GmmMagnitudeUsage): void { + this.spinnerService.remove(); + const parameters = usageResponse.response.parameters; + const values = usageFormValues(parameters); + + this.formGroup.patchValue({ + ...values, + }); + + const serviceCallInfo: ServiceCallInfo = { + ...this.state().serviceCallInfo, + usage: [this.serviceUrl], + }; + + this.updateState({ + serviceCallInfo, + usageResponse, + }); + + this.spinnerService.remove(); } } diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/state/app.reducer.ts b/projects/nshmp-apps/src/app/gmm/magnitude/state/app.reducer.ts deleted file mode 100644 index 137ee7d8a54edd50ec5a48e1dac39a64d2d90215..0000000000000000000000000000000000000000 --- a/projects/nshmp-apps/src/app/gmm/magnitude/state/app.reducer.ts +++ /dev/null @@ -1,296 +0,0 @@ -import {GmmFormControlIds, gmmUtils} from '@ghsc/nshmp-lib-ng/gmm'; -import {NshmpPlot} from '@ghsc/nshmp-lib-ng/plot'; -import {createFeature, createReducer, createSelector, on} from '@ngrx/store'; -import { - box, - createFormGroupState, - disable, - enable, - onNgrxForms, - onNgrxFormsAction, - setValue, - SetValueAction, - unbox, - updateGroup, - wrapReducerWithFormStateUpdate, -} from 'ngrx-forms'; -import {environment} from 'projects/nshmp-apps/src/environments/environment'; -import { - onPlotRedraw, - onPlotSettingsForm, - onResetSetting, -} from 'projects/nshmp-apps/src/shared/state/shared'; - -import {GmmMagnitudeFormControls} from '../models/gmm-magnitude-form-controls.model'; -import { - defaultFormValues, - defaultPlots, - MEAN_PLOT_SETTING_ID, - SIGMA_PLOT_SETTING_ID, -} from '../utils/app.default-values'; -import {validateControlPanelForm} from '../utils/control-panel.validators'; -import {serviceResponseToPlotData} from '../utils/response.handler'; -import {actions} from './app.actions'; -import {AppState, CONTROL_FORM_ID, INITIAL_STATE} from './app.state'; - -/** Form state key ids */ -const formKeys = { - control: { - gmmSource: `${CONTROL_FORM_ID}.${GmmFormControlIds.GMM_SOURCE}`, - multiSelectable: `${CONTROL_FORM_ID}.${GmmFormControlIds.MULTI_SELECTABLE_PARAM}`, - Mw: `${CONTROL_FORM_ID}.${GmmFormControlIds.MW}`, - showEpistemicUncertainty: `${CONTROL_FORM_ID}.${GmmFormControlIds.SHOW_EPISTEMIC_UNCERTAINTY}`, - vs30: `${CONTROL_FORM_ID}.${GmmFormControlIds.VS30}`, - }, - settings: { - mean: MEAN_PLOT_SETTING_ID, - sigma: SIGMA_PLOT_SETTING_ID, - }, -}; - -const baseUrl = environment.webServices.data.url; -const endpoint = environment.webServices.data.services.gmmMagnitude; -const serviceUrl = `${baseUrl}${endpoint}`; - -/** - * NGRX application raw reducer. - */ -export const magnitudeAppFeature = createFeature({ - extraSelectors: ({selectPlots}) => ({ - selectMeanPlot: createSelector(selectPlots, plots => - plots.get(gmmUtils.PlotType.MEANS) - ), - selectSigmaPlot: createSelector(selectPlots, plots => - plots.get(gmmUtils.PlotType.SIGMA) - ), - }), - name: 'gmmMagnitudeApp', - reducer: createReducer( - /** Application intitial sate */ - INITIAL_STATE, - /* On NGRX forms */ - onNgrxForms(), - /* On form change */ - onNgrxFormsAction(SetValueAction, (state, action) => { - const clearPlots = new Map<string, NshmpPlot>(); - - state.plots.forEach((plot, key) => - clearPlots.set(key, { - ...plot, - plotData: { - ...plot.plotData, - data: [ - ...plot.plotData.data.map(data => { - data = {...data}; - data.x = []; - data.y = []; - return data; - }), - ], - }, - }) - ); - - const clearState: AppState = { - ...state, - controlForm: updateGroup<GmmMagnitudeFormControls>({ - showEpistemicUncertainty: control => - disable(setValue(control, false)), - })(state.controlForm), - plots: clearPlots, - serviceResponses: null, - }; - - switch (action.controlId) { - case formKeys.control.multiSelectable: { - let form = {...clearState.controlForm}; - const parameters = - clearState.usageResponses?.response?.parameters || null; - - if (form.value.multiSelectableParam === GmmFormControlIds.VS30) { - form = updateGroup<GmmMagnitudeFormControls>({ - gmmSource: gmm => setValue(gmm, box([])), - vs30: vs30 => - setValue(vs30, (parameters.vs30.value as number) || null), - vs30Multi: vs30 => setValue(vs30, box([])), - })(clearState.controlForm); - } - - return { - ...clearState, - controlForm: form, - serviceCallInfo: gmmUtils.serviceCallInfo({ - multiSelectableParam: form.value.multiSelectableParam, - serviceName: clearState.serviceCallInfo.serviceName, - serviceResponses: clearState.serviceResponses, - serviceUrl, - values: form.value, - }), - }; - } - case formKeys.control.gmmSource: { - const gmm = unbox(clearState.controlForm.value.gmmSource); - const serviceCallInfo = gmmUtils.serviceCallInfo({ - multiSelectableParam: - clearState.controlForm.value.multiSelectableParam, - serviceName: clearState.serviceCallInfo.serviceName, - serviceResponses: clearState.serviceResponses, - serviceUrl, - values: clearState.controlForm.value, - }); - - if ( - clearState.usageResponses && - clearState.controlForm.controls.gmmSource && - gmm.length > 0 - ) { - const supportedImts = gmmUtils.getSupportedImts( - gmm, - clearState.usageResponses - ); - - const controlForm = gmmUtils.onGmmChange( - clearState.controlForm, - supportedImts - ); - - return { - ...clearState, - controlForm, - serviceCallInfo, - supportedImts, - }; - } - return { - ...clearState, - serviceCallInfo, - }; - } - case formKeys.control.showEpistemicUncertainty: { - return { - ...state, - plots: serviceResponseToPlotData(state), - }; - } - default: { - if ( - action.controlId.includes(formKeys.settings.mean) || - action.controlId.includes(formKeys.settings.sigma) - ) { - return onPlotSettingsForm(state, action); - } else { - return { - ...clearState, - serviceCallInfo: gmmUtils.serviceCallInfo({ - multiSelectableParam: - clearState.controlForm.value.multiSelectableParam, - serviceName: clearState.serviceCallInfo.serviceName, - serviceResponses: clearState.serviceResponses, - serviceUrl, - values: clearState.controlForm.value, - }), - }; - } - } - } - }), - /* On init action */ - on(actions.init, () => { - return { - ...INITIAL_STATE, - }; - }), - /* On reset control panel action */ - on(actions.resetControlPanel, state => { - const controlForm = createFormGroupState<GmmMagnitudeFormControls>( - CONTROL_FORM_ID, - defaultFormValues(state.usageResponses.response.parameters) - ); - - state = { - ...state, - controlForm, - plots: INITIAL_STATE.plots, - serviceCallInfo: INITIAL_STATE.serviceCallInfo, - serviceResponses: INITIAL_STATE.serviceResponses, - }; - - return { - ...state, - serviceCallInfo: gmmUtils.serviceCallInfo({ - multiSelectableParam: state.controlForm.value.multiSelectableParam, - serviceName: state.serviceCallInfo.serviceName, - serviceResponses: state.serviceResponses, - serviceUrl, - values: state.controlForm.value, - }), - }; - }), - /* On reset plot settings action */ - on(actions.resetSettings, state => { - return onResetSetting(state, defaultPlots()); - }), - /* On plots action */ - on(actions.plots, (state, {plots}) => { - return { - ...state, - plots, - }; - }), - /* On plot redraw action */ - on(actions.plotRedraw, state => { - return onPlotRedraw(state); - }), - /* On service response action */ - on(actions.serviceResponse, (state, {serviceResponses}) => { - const means = serviceResponses.map(s => s.response.means); - const sigmas = serviceResponses.map(s => s.response.sigmas); - const hasLogicTree = gmmUtils.hasTree([...means, ...sigmas]); - - state = { - ...state, - controlForm: updateGroup<GmmMagnitudeFormControls>({ - showEpistemicUncertainty: hasLogicTree ? enable : disable, - })(state.controlForm), - serviceResponses, - }; - - return { - ...state, - serviceCallInfo: gmmUtils.serviceCallInfo({ - multiSelectableParam: state.controlForm.value.multiSelectableParam, - serviceName: state.serviceCallInfo.serviceName, - serviceResponses: state.serviceResponses, - serviceUrl, - values: state.controlForm.value, - }), - }; - }), - /* On service call info action */ - on(actions.serviceCallInfo, (state, {serviceCallInfo}) => { - return { - ...state, - serviceCallInfo: { - ...state.serviceCallInfo, - ...serviceCallInfo, - }, - }; - }), - /* On usage response action */ - on(actions.usageResponse, (state, {usageResponses}) => { - return { - ...state, - usageResponses, - }; - }) - ), -}); - -/** - * Application NGRX reducer with validators. - */ -magnitudeAppFeature.reducer = wrapReducerWithFormStateUpdate( - magnitudeAppFeature.reducer, - state => state.controlForm, - validateControlPanelForm -); diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/state/app.state.ts b/projects/nshmp-apps/src/app/gmm/magnitude/state/app.state.ts index d76a922d04d83d228d475fb0b084d272f6b74d97..2bddf912dfe3433295db359ab59bdf6429c73832 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/state/app.state.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/state/app.state.ts @@ -1,45 +1,18 @@ -import {ServiceCallInfo} from '@ghsc/nshmp-lib-ng/nshmp'; +import {ServiceCallInfo} from '@ghsc/nshmp-lib-no-ngrx/nshmp'; +import {NshmpPlot} from '@ghsc/nshmp-lib-no-ngrx/plot'; import { GmmMagnitudeResponse, GmmMagnitudeUsage, } from '@ghsc/nshmp-utils-ts/libs/nshmp-ws/gmm-services'; import {EnumParameterValues} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws-utils/metadata'; -import { - createFormGroupState, - disable, - FormGroupState, - updateGroup, -} from 'ngrx-forms'; -import {SharedAppState} from 'projects/nshmp-apps/src/shared/state/shared'; - -import {GmmMagnitudeFormControls} from '../models/gmm-magnitude-form-controls.model'; -import {DEFAULT_FORM_VALUES, defaultPlots} from '../utils/app.default-values'; - -/** Control form id for ngrx-forms */ -export const CONTROL_FORM_ID = '[ngrx-forms] GM vs. Magnitude App Control Form'; -const formState = createFormGroupState<GmmMagnitudeFormControls>( - CONTROL_FORM_ID, - { - ...DEFAULT_FORM_VALUES, - } -); - -/** - * Initial state for the control panel - */ -export const INITIAL_CONTROL_FORM_STATE = updateGroup<GmmMagnitudeFormControls>( - { - showEpistemicUncertainty: disable, - } -)(formState); +import {defaultPlots} from '../utils/app.default-values'; /** * GMM magnitude app state. */ -export interface AppState extends SharedAppState { - /** Control panel form field state */ - controlForm: FormGroupState<GmmMagnitudeFormControls>; +export interface AppState { + plots: Map<string, NshmpPlot>; /** Service call info */ serviceCallInfo: ServiceCallInfo; /** GMM service response */ @@ -47,21 +20,20 @@ export interface AppState extends SharedAppState { /** Supported IMTs */ supportedImts: EnumParameterValues[]; /** GMM usages */ - usageResponses: GmmMagnitudeUsage; + usageResponse: GmmMagnitudeUsage; } /** * GMM magnitude app inital state. */ export const INITIAL_STATE: AppState = { - controlForm: INITIAL_CONTROL_FORM_STATE, plots: defaultPlots(), serviceCallInfo: { serviceCalls: [], serviceName: 'Ground Motion vs. Magnitude', - usage: null, + usage: [], }, serviceResponses: [], supportedImts: [], - usageResponses: null, + usageResponse: null, }; diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/utils/app.default-values.ts b/projects/nshmp-apps/src/app/gmm/magnitude/utils/app.default-values.ts index 88b44121b7415fc718b7e3c2056774934b4674b4..fa7be0c7194f8ed5bdfe1e2be6efb6deaf17028f 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/utils/app.default-values.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/utils/app.default-values.ts @@ -1,15 +1,14 @@ -import {GmmSource, gmmUtils} from '@ghsc/nshmp-lib-ng/gmm'; +import {gmmUtils} from '@ghsc/nshmp-lib-no-ngrx/gmm'; import { NshmpPlot, NshmpPlotSettings, PlotOptions, plotUtils, -} from '@ghsc/nshmp-lib-ng/plot'; +} from '@ghsc/nshmp-lib-no-ngrx/plot'; import { GmmGroupType, GmmMagnitudeUsageParameters, } from '@ghsc/nshmp-utils-ts/libs/nshmp-ws/gmm-services'; -import {box, createFormGroupState} from 'ngrx-forms'; import { FormControlIds, @@ -27,7 +26,7 @@ export const DEFAULT_FORM_VALUES: GmmMagnitudeFormControls = { dip: null, distance: null, gmmGroupType: GmmGroupType.ACTIVE_CRUST, - gmmSource: box([] as GmmSource[]), + gmmSource: [], imt: 'default', mMax: null, mMin: null, @@ -36,7 +35,7 @@ export const DEFAULT_FORM_VALUES: GmmMagnitudeFormControls = { showEpistemicUncertainty: false, step: null, vs30: null, - vs30Multi: box([] as number[]), + vs30Multi: [], width: null, z1p0: null, z2p5: null, @@ -49,7 +48,7 @@ export const DEFAULT_FORM_VALUES: GmmMagnitudeFormControls = { * * @param parameters The service parameters */ -export function defaultFormValues( +export function usageFormValues( parameters: GmmMagnitudeUsageParameters ): GmmMagnitudeFormControls { return { @@ -76,22 +75,12 @@ export const defaultPlots = (): Map<string, NshmpPlot> => { plots.set(gmmUtils.PlotType.MEANS, { label: 'Response Spectra', plotData: meanPlotData, - settingsForm: createFormGroupState<NshmpPlotSettings>( - MEAN_PLOT_SETTING_ID, - { - ...meanSettingsForm, - } - ), + settingsForm: plotUtils.plotSettingsToFormGroup(meanSettingsForm), }); plots.set(gmmUtils.PlotType.SIGMA, { label: 'Standard Deviation', plotData: sigmaPlotData, - settingsForm: createFormGroupState<NshmpPlotSettings>( - SIGMA_PLOT_SETTING_ID, - { - ...sigmaSettingsForm, - } - ), + settingsForm: plotUtils.plotSettingsToFormGroup(sigmaSettingsForm), }); return new Map(plots); }; diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/utils/response.handler.ts b/projects/nshmp-apps/src/app/gmm/magnitude/utils/response.handler.ts index 22baeb0c99988de1301938bf006b0c2daa55b51a..65712ca717b16813f9336c955f55e3c5b58b8870 100644 --- a/projects/nshmp-apps/src/app/gmm/magnitude/utils/response.handler.ts +++ b/projects/nshmp-apps/src/app/gmm/magnitude/utils/response.handler.ts @@ -1,8 +1,11 @@ -import {gmmUtils} from '@ghsc/nshmp-lib-ng/gmm'; -import {NshmpPlot} from '@ghsc/nshmp-lib-ng/plot'; +import {gmmUtils} from '@ghsc/nshmp-lib-no-ngrx/gmm'; +import {FormGroupControls} from '@ghsc/nshmp-lib-no-ngrx/nshmp'; +import {NshmpPlot} from '@ghsc/nshmp-lib-no-ngrx/plot'; import {XySequence} from '@ghsc/nshmp-utils-ts/libs/nshmp-lib/data'; +import {GmmMagnitudeFormControls} from '../models/gmm-magnitude-form-controls.model'; import {AppState} from '../state/app.state'; +import {defaultPlots} from './app.default-values'; /** * Transform Gmm distance service responses to plots. @@ -10,15 +13,17 @@ import {AppState} from '../state/app.state'; * @param state The application state */ export function serviceResponseToPlotData( - state: AppState + state: AppState, + form: FormGroupControls<GmmMagnitudeFormControls> ): Map<string, NshmpPlot> { - if (state.serviceResponses.length === 0) { - return state.plots; + if (state.serviceResponses === null || state.serviceResponses?.length === 0) { + return defaultPlots(); } + const plots = new Map<string, NshmpPlot>(); const meanPlot = state.plots.get(gmmUtils.PlotType.MEANS); const sigmaPlot = state.plots.get(gmmUtils.PlotType.SIGMA); - const formValues = state.controlForm.value; + const formValues = form.getRawValue(); const responses: gmmUtils.GmmResponse<XySequence, number[]>[] = state.serviceResponses.map(serviceResponse => ({