From c5c600e9fb8f32d8d2b3a8c01d58c7c536049cb7 Mon Sep 17 00:00:00 2001 From: Brandon Clayton <bclayton@usgs.gov> Date: Mon, 29 Jul 2024 12:42:57 -0600 Subject: [PATCH 01/10] remove state --- projects/nshmp-apps/src/app/gmm/gmm.routes.ts | 6 - .../app/gmm/magnitude/state/app.actions.ts | 22 -- .../app/gmm/magnitude/state/app.effects.ts | 147 --------- .../app/gmm/magnitude/state/app.reducer.ts | 296 ------------------ 4 files changed, 471 deletions(-) delete mode 100644 projects/nshmp-apps/src/app/gmm/magnitude/state/app.actions.ts delete mode 100644 projects/nshmp-apps/src/app/gmm/magnitude/state/app.effects.ts delete mode 100644 projects/nshmp-apps/src/app/gmm/magnitude/state/app.reducer.ts diff --git a/projects/nshmp-apps/src/app/gmm/gmm.routes.ts b/projects/nshmp-apps/src/app/gmm/gmm.routes.ts index 52138a14c..b20f1a872 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/state/app.actions.ts b/projects/nshmp-apps/src/app/gmm/magnitude/state/app.actions.ts deleted file mode 100644 index 26382a0d2..000000000 --- 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 a45bc5824..000000000 --- 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.reducer.ts b/projects/nshmp-apps/src/app/gmm/magnitude/state/app.reducer.ts deleted file mode 100644 index 137ee7d8a..000000000 --- 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 -); -- GitLab From 49fe02840d5a931573aafeacbbfeda4cd6c42b8a Mon Sep 17 00:00:00 2001 From: Brandon Clayton <bclayton@usgs.gov> Date: Mon, 29 Jul 2024 12:43:07 -0600 Subject: [PATCH 02/10] switch to signals and reactive forms --- .../control-panel/control-panel.component.ts | 7 +- .../components/content/content.component.html | 16 +- .../components/content/content.component.ts | 39 +-- .../control-panel.component.html | 113 +++++---- .../control-panel/control-panel.component.ts | 121 +++++++-- .../event-parameters.component.html | 118 +++++---- .../event-parameters.component.ts | 40 +-- .../parameter-summary.component.html | 157 ++++++------ .../parameter-summary.component.ts | 14 +- .../path-parameters.component.html | 48 ++-- .../path-parameters.component.ts | 38 +-- .../plots-settings.component.html | 19 +- .../plots-settings.component.ts | 31 ++- .../components/plots/plots.component.html | 14 +- .../components/plots/plots.component.ts | 15 +- .../site-parameters.component.html | 142 ++++++----- .../site-parameters.component.ts | 44 ++-- .../source-parameters.component.html | 120 +++++---- .../source-parameters.component.ts | 32 ++- .../gmm-magnitude-form-controls.model.ts | 5 +- .../src/app/gmm/magnitude/state/app.facade.ts | 229 +++++++++++++++--- .../src/app/gmm/magnitude/state/app.state.ts | 44 +--- .../gmm/magnitude/utils/app.default-values.ts | 25 +- .../gmm/magnitude/utils/response.handler.ts | 17 +- 24 files changed, 842 insertions(+), 606 deletions(-) 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 e4718bf16..de3142140 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/magnitude/components/content/content.component.html b/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.html index 3ce3d99ca..045a08715 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.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/content/content.component.ts index b67a804fd..f8561f3c8 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 f9fb679e7..4fa3ff227 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.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.ts index 6f463e6b5..19933c757 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,19 +1,20 @@ 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 {EventParametersComponent} from '../event-parameters/event-parameters.component'; @@ -38,41 +39,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 +107,62 @@ 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.gmmSource.setValue([]); + this.controls.Mw.setValue(parameters.Mw.value as number); + this.controls.MwMulti.setValue([]); + } else if (multiSelectableParam === GmmFormControlIds.VS30) { + this.controls.gmmSource.setValue([]); + this.controls.vs30.setValue(parameters.vs30.value as number); + this.controls.vs30Multi.setValue([]); + } + + 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 bab977bfd..f0a3b452d 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.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.ts index b9494f380..ddff30560 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 f0044425a..06e1589fb 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.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.ts index 166e75cec..ea07924b4 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 ca22b23d1..b397645ef 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.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.ts index 4608ac623..1ca9f5cfd 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 82d44ff07..cb9c55121 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) { + @if (sigmaPlot()) { <nshmp-lib-ng-plot-settings - [plot]="sigmaPlot$ | async" + [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.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.ts index 483f71ff8..3e6c0e88d 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 a18cbd37e..dac5eeac1 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.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.ts index 7800906fb..8088793cd 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 782f79c8b..6389406f3 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.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.ts index f71aeb052..bc789827a 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 d76769447..b391b897e 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.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.ts index 4a4c59310..8ce5cdead 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 ea75d6a0f..2d1c266e7 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.facade.ts b/projects/nshmp-apps/src/app/gmm/magnitude/state/app.facade.ts index 0e09fe9ab..28c3ff154 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.state.ts b/projects/nshmp-apps/src/app/gmm/magnitude/state/app.state.ts index d76a922d0..2bddf912d 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 88b44121b..fa7be0c71 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 22baeb0c9..65712ca71 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 => ({ -- GitLab From c4bce0b27c3100ec6ac1fed18c7edbb715dbdbe2 Mon Sep 17 00:00:00 2001 From: Brandon Clayton <bclayton@usgs.gov> Date: Mon, 29 Jul 2024 12:51:24 -0600 Subject: [PATCH 03/10] add providers --- .../magnitude/components/content/content.component.spec.ts | 7 ++----- .../control-panel/control-panel.component.spec.ts | 4 ++-- .../event-parameters/event-parameters.component.spec.ts | 4 +++- .../parameter-summary/parameter-summary.component.spec.ts | 4 ++-- .../path-parameters/path-parameters.component.spec.ts | 5 +++-- .../plots-settings/plots-settings.component.html | 2 +- .../plots-settings/plots-settings.component.spec.ts | 4 ++-- .../gmm/magnitude/components/plots/plots.component.spec.ts | 7 +------ .../site-parameters/site-parameters.component.spec.ts | 5 +++-- .../source-parameters/source-parameters.component.spec.ts | 5 +++-- 10 files changed, 22 insertions(+), 25 deletions(-) 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 4a22de1da..3b3a0a2f3 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/control-panel/control-panel.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/control-panel/control-panel.component.spec.ts index dd4d4d086..524a65d03 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/event-parameters/event-parameters.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/event-parameters/event-parameters.component.spec.ts index c46328c70..1fbfb9d01 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 @@ -2,6 +2,8 @@ import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; import {provideMockStore} from '@ngrx/store/testing'; import {EventParametersComponent} from './event-parameters.component'; +import {provideHttpClient} from '@angular/common/http'; +import {provideNoopAnimations} from '@angular/platform-browser/animations'; describe('EventParametersComponent', () => { let component: EventParametersComponent; @@ -10,7 +12,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/parameter-summary/parameter-summary.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/parameter-summary/parameter-summary.component.spec.ts index d8af63c07..b8d5719b6 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/path-parameters/path-parameters.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/path-parameters/path-parameters.component.spec.ts index 874eb64c8..7a9ef8898 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/plots-settings/plots-settings.component.html b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots-settings/plots-settings.component.html index cb9c55121..a7d0427a7 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 @@ -8,7 +8,7 @@ } @if (sigmaPlot()) { - <nshmp-lib-ng-plot-settings + <nshmp-lib-no-ngrx-plot-settings [plot]="sigmaPlot()" (updatedPlot)="updatePlot(PlotIds.SIGMA, $event)" class="sigma-settings" 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 2d559563d..f32cb4991 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/plots.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/plots/plots.component.spec.ts index 611faa48c..12310e664 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/site-parameters/site-parameters.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/site-parameters/site-parameters.component.spec.ts index b7857664b..e6ed2c402 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/source-parameters/source-parameters.component.spec.ts b/projects/nshmp-apps/src/app/gmm/magnitude/components/source-parameters/source-parameters.component.spec.ts index a3e89bc20..a2e4133e6 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(); })); -- GitLab From 9b36be79aca86fd01a241fc3bc1488a142089c19 Mon Sep 17 00:00:00 2001 From: Brandon Clayton <bclayton@usgs.gov> Date: Mon, 29 Jul 2024 13:09:07 -0600 Subject: [PATCH 04/10] lint fix --- .../event-parameters/event-parameters.component.spec.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 1fbfb9d01..ea17eb0a6 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,9 +1,8 @@ +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'; -import {provideHttpClient} from '@angular/common/http'; -import {provideNoopAnimations} from '@angular/platform-browser/animations'; describe('EventParametersComponent', () => { let component: EventParametersComponent; -- GitLab From 3caf8b776686ed258d1f4b416aeb96a5136c1907 Mon Sep 17 00:00:00 2001 From: Brandon Clayton <bclayton@usgs.gov> Date: Tue, 30 Jul 2024 09:46:02 -0600 Subject: [PATCH 05/10] reset gmm on change --- .../components/control-panel/control-panel.component.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 19933c757..b83e99fee 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 @@ -17,6 +17,7 @@ import { 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'; @@ -146,15 +147,16 @@ export class ControlPanelComponent implements OnInit, OnDestroy { const parameters = this.facade.state().usageResponse.response.parameters; if (multiSelectableParam === GmmFormControlIds.MW) { - this.controls.gmmSource.setValue([]); this.controls.Mw.setValue(parameters.Mw.value as number); this.controls.MwMulti.setValue([]); } else if (multiSelectableParam === GmmFormControlIds.VS30) { - this.controls.gmmSource.setValue([]); 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(); } -- GitLab From 82f16679009bb6da4f93b5f0655ed752d5d4c256 Mon Sep 17 00:00:00 2001 From: Brandon Clayton <bclayton@usgs.gov> Date: Tue, 30 Jul 2024 10:05:54 -0600 Subject: [PATCH 06/10] test --- .gitlab-ci.yml | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2b4c52c35..0fb2c716a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,7 +2,7 @@ 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 + # 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 @@ -150,25 +150,25 @@ 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 +# 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 @@ -179,8 +179,8 @@ Build Project: paths: - dist before_script: - - git config --global --add safe.directory '*' - image: ${NODE_IMAGE} + # - git config --global --add safe.directory '*' + # image: ${NODE_IMAGE} needs: - Init - Build Node Image -- GitLab From d48be5da7e819c66eb14a9c35f9c23c91ce73687 Mon Sep 17 00:00:00 2001 From: Brandon Clayton <bclayton@usgs.gov> Date: Tue, 30 Jul 2024 10:06:10 -0600 Subject: [PATCH 07/10] test --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0fb2c716a..f4c8cc740 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -178,12 +178,12 @@ Build Project: artifacts: paths: - dist - before_script: + # before_script: # - git config --global --add safe.directory '*' # image: ${NODE_IMAGE} needs: - Init - - Build Node Image + # - Build Node Image script: - npm run build:prod stage: build -- GitLab From 72ea56e4a331b6f71a73c571f1d9d191f45c06e8 Mon Sep 17 00:00:00 2001 From: Brandon Clayton <bclayton@usgs.gov> Date: Tue, 30 Jul 2024 10:13:12 -0600 Subject: [PATCH 08/10] remove image --- .gitlab-ci.yml | 25 ------------------------- .gitlab/Dockerfile | 9 --------- 2 files changed, 34 deletions(-) delete mode 100644 .gitlab/Dockerfile diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f4c8cc740..8672e48c8 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 @@ -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,12 +157,8 @@ Build Project: artifacts: paths: - dist - # before_script: - # - git config --global --add safe.directory '*' - # image: ${NODE_IMAGE} needs: - Init - # - Build Node Image script: - npm run build:prod stage: build diff --git a/.gitlab/Dockerfile b/.gitlab/Dockerfile deleted file mode 100644 index c5a2d0ec8..000000000 --- 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 -- GitLab From a311941c865803f745c85cfa9aa9b2903dfc1fbb Mon Sep 17 00:00:00 2001 From: Brandon Clayton <bclayton@usgs.gov> Date: Tue, 30 Jul 2024 11:30:19 -0600 Subject: [PATCH 09/10] switch image --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8672e48c8..ecc444dae 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -74,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 -- GitLab From 87951f59042e319b26ac71b7cce5946740f33bfc Mon Sep 17 00:00:00 2001 From: Brandon Clayton <bclayton@usgs.gov> Date: Tue, 30 Jul 2024 11:36:34 -0600 Subject: [PATCH 10/10] install git --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ecc444dae..eec4be44e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -160,6 +160,7 @@ Build Project: needs: - Init script: + - apt-get install -y git - npm run build:prod stage: build -- GitLab