diff --git a/projects/nshmp-apps/src/app/dev/aws/aws.routes.ts b/projects/nshmp-apps/src/app/dev/aws/aws.routes.ts index 972f527821396f5e2dad32613630945c81827bce..aade7d84d87244e92d933b2e353e92a880c9590f 100644 --- a/projects/nshmp-apps/src/app/dev/aws/aws.routes.ts +++ b/projects/nshmp-apps/src/app/dev/aws/aws.routes.ts @@ -2,8 +2,6 @@ import {Routes} from '@angular/router'; import {provideEffects} from '@ngrx/effects'; import {provideState} from '@ngrx/store'; -import {SubmitHazJobsAppEffects} from './submit-haz-jobs/state/app.effects'; -import {submitHazJobsAppFeature} from './submit-haz-jobs/state/app.reducer'; import {TerminateHazJobsAppEffects} from './terminate-haz-jobs/state/app.effect'; import {terminateHazJobsAppFeature} from './terminate-haz-jobs/state/app.reducer'; @@ -33,10 +31,6 @@ const routes: Routes = [ loadComponent: () => import('./submit-haz-jobs/app.component').then(com => com.AppComponent), path: 'submit-haz-jobs', - providers: [ - provideState(submitHazJobsAppFeature), - provideEffects(SubmitHazJobsAppEffects), - ], }, ]; diff --git a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/form/form.component.html b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/form/form.component.html index e378e3dbc99aa6c8a6e6687bf3e663e247987220..a13ab87232b00efc8615d64abf6a1afe9ec664a5 100644 --- a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/form/form.component.html +++ b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/form/form.component.html @@ -1,674 +1,600 @@ -@if (form$ | async; as form) { - <div class="grid-container-desktop-lg center-x"> - <nshmp-template-form-fields> - <form - class="settings-section width-full padding-top-3" - [ngrxFormState]="form" - (submit)="facade.callService()" - > - <mat-accordion multi> - <!-- Import section --> - <mat-expansion-panel expanded> - <mat-expansion-panel-header> - <mat-panel-title>Configuration Import</mat-panel-title> - </mat-expansion-panel-header> - - <mat-divider /> - - <div class="settings-subsection import-section"> - <div class="settings-subsection--section"> - <!-- Import: file upload --> - <div> - Already have the below information? <br /> - Import the - <a (click)="appService.activeTab(configTab.position)"> - configuration - </a> - as - <a (click)="appService.activeTab(jsonTab.position)">JSON</a> - or - <a (click)="appService.activeTab(yamlTab.position)">YAML</a> - </div> - <br /> - <input - #config - type="file" - accept=".json,.yml,.yaml" - (change)="importConfigFile()" - /> +<div class="grid-container-desktop-lg center-x"> + <nshmp-template-form-fields> + <form + class="settings-section width-full padding-top-3" + [formGroup]="form" + (submit)="facade.callService()" + > + <mat-accordion multi> + <!-- Import section --> + <mat-expansion-panel expanded> + <mat-expansion-panel-header> + <mat-panel-title>Configuration Import</mat-panel-title> + </mat-expansion-panel-header> + + <mat-divider /> + + <div class="settings-subsection import-section"> + <div class="settings-subsection--section"> + <!-- Import: file upload --> + <div> + Already have the below information? <br /> + Import the + <a (click)="appService.activeTab(configTab.position)"> + configuration + </a> + as + <a (click)="appService.activeTab(jsonTab.position)">JSON</a> + or + <a (click)="appService.activeTab(yamlTab.position)">YAML</a> </div> + <br /> + <input + #configEl + type="file" + accept=".json,.yml,.yaml" + (change)="importConfigFile()" + /> </div> - </mat-expansion-panel> - - <!-- Cloud config--> - <mat-expansion-panel expanded> - <mat-expansion-panel-header> - <mat-panel-title>Cloud Configuration</mat-panel-title> - </mat-expansion-panel-header> - - <mat-divider /> - - <div class="settings-subsection aws-section"> - <div class="settings-subsection--section"> - <!-- AWS information: instance type --> - <mat-form-field class="grid-col-12 tablet:grid-col-6"> - <mat-label> - AWS EC2 Isntance Type - <span class="form-required">*</span> - </mat-label> - <input - matInput - type="text" - [ngrxFormControlState]=" - form.controls.cloudConfig.controls.instanceType - " - /> - <span matPrefix> - <mat-icon aria-label="Memory icon" fontIcon="memory" /> - </span> - <a - matSuffix - mat-icon-button - matTooltip="Click for AWS EC2 isntance type info" - href="https://aws.amazon.com/ec2/instance-types/" - target="__blank" - color="primary" - > - <mat-icon aria-label="Info icon" fontIcon="info" /> - </a> - <mat-hint> The AWS EC2 instance type </mat-hint> - <mat-error>Must not contain spaces</mat-error> - </mat-form-field> - - <p>Common instance types:</p> - <ul class="usa-list"> - @for (instance of commonInstances; track instance) { - <li> - {{ instance.type }} - (CPU: {{ instance.cpu }}, Memory: {{ instance.mem }} GB) - </li> - } - </ul> - </div> + </div> + </mat-expansion-panel> + + <!-- Cloud config--> + <mat-expansion-panel expanded> + <mat-expansion-panel-header> + <mat-panel-title>Cloud Configuration</mat-panel-title> + </mat-expansion-panel-header> + + <mat-divider /> + + <div class="settings-subsection aws-section"> + <div class="settings-subsection--section"> + <!-- AWS information: instance type --> + <mat-form-field class="grid-col-12 tablet:grid-col-6"> + <mat-label> + AWS EC2 Isntance Type + <span class="form-required">*</span> + </mat-label> + <input + matInput + type="text" + [formControl]=" + form.controls.cloudConfig.controls.instanceType + " + /> + <span matPrefix> + <mat-icon aria-label="Memory icon" fontIcon="memory" /> + </span> + <a + matSuffix + mat-icon-button + matTooltip="Click for AWS EC2 isntance type info" + href="https://aws.amazon.com/ec2/instance-types/" + target="__blank" + color="primary" + > + <mat-icon aria-label="Info icon" fontIcon="info" /> + </a> + <mat-hint> The AWS EC2 instance type </mat-hint> + <mat-error>Must not contain spaces</mat-error> + </mat-form-field> + + <p>Common instance types:</p> + <ul class="usa-list"> + @for (instance of commonInstances; track instance) { + <li> + {{ instance.type }} + (CPU: {{ instance.cpu }}, Memory: {{ instance.mem }} GB) + </li> + } + </ul> </div> - </mat-expansion-panel> - - <!-- NSHMP Config section --> - <mat-expansion-panel expanded> - <mat-expansion-panel-header> - <mat-panel-title>NSHMP Configuration</mat-panel-title> - </mat-expansion-panel-header> - <mat-divider /> - <div class="settings-subsection program-section"> - <div class="settings-subsection--section"> - <!-- NSHMP config: email --> - <mat-form-field class="grid-col-12 tablet:grid-col-6"> - <mat-label - >Email <span class="form-required">*</span></mat-label - > - <input - matInput - [ngrxFormControlState]=" - form.controls.nshmpConfig.controls.email - " - /> - <span matPrefix> - <mat-icon aria-label="Email icon" fontIcon="email" /> - </span> - @if ( - (form$ | async)?.errors?._nshmpConfig?._email?.pattern - ?.pattern === whitespace - ) { - <mat-error> Must not contain spaces </mat-error> - } @else { - <mat-error>Must be a valid USGS email</mat-error> - } - <mat-hint>Email to recieve notifications from AWS</mat-hint> - </mat-form-field> - - <mat-divider /> - - <!-- NSHMP config: Source code --> - <div class="settings-subsection padding-top-1"> - <mat-label class="settings-subsection--label"> - nshmp-haz Source Code - </mat-label> - <div class="settings-subsection--section"> - <!-- NSHMP config: source code Git URL --> - <mat-form-field class="grid-col-12"> - <mat-label> - Source Code Git URL - <span class="form-required">*</span> - </mat-label> - <input - matInput - type="text" - [ngrxFormControlState]=" - form.controls.nshmpConfig.controls.sourceCodeGitUrl - " - /> - <span matPrefix> - <mat-icon aria-label="Code icon" fontIcon="code" /> - </span> - <a - matSuffix - mat-icon-button - matTooltip="Click for GitLab git clone URL info" - href="https://docs.gitlab.com/ee/gitlab-basics/start-using-git.html#clone-with-https" - target="__blank" - color="primary" - > - <mat-icon aria-label="Info icon" fontIcon="info" /> - </a> - @if ( - (form$ | async)?.errors?._nshmpConfig?._sourceCodeGitUrl - ?.pattern?.pattern === whitespace - ) { - <mat-error> Must not contain spaces </mat-error> - } @else { - <mat-error> - Must be a valid URL ending in <code>.git</code> - </mat-error> + </div> + </mat-expansion-panel> + + <!-- NSHMP Config section --> + <mat-expansion-panel expanded> + <mat-expansion-panel-header> + <mat-panel-title>NSHMP Configuration</mat-panel-title> + </mat-expansion-panel-header> + <mat-divider /> + <div class="settings-subsection program-section"> + <div class="settings-subsection--section"> + <!-- NSHMP config: email --> + <mat-form-field class="grid-col-12 tablet:grid-col-6"> + <mat-label + >Email <span class="form-required">*</span></mat-label + > + <input + matInput + [formControl]="form.controls.nshmpConfig.controls.email" + /> + <span matPrefix> + <mat-icon aria-label="Email icon" fontIcon="email" /> + </span> + <mat-error>Must be a valid USGS email</mat-error> + <mat-hint>Email to recieve notifications from AWS</mat-hint> + </mat-form-field> + + <mat-divider /> + + <!-- NSHMP config: Source code --> + <div class="settings-subsection padding-top-1"> + <mat-label class="settings-subsection--label"> + nshmp-haz Source Code + </mat-label> + <div class="settings-subsection--section"> + <!-- NSHMP config: source code Git URL --> + <mat-form-field class="grid-col-12 tablet:grid-col-12"> + <mat-label> + Source Code Git URL + <span class="form-required">*</span> + </mat-label> + <input + matInput + type="text" + [formControl]=" + form.controls.nshmpConfig.controls.sourceCodeGitUrl + " + /> + <span matPrefix> + <mat-icon aria-label="Code icon" fontIcon="code" /> + </span> + <a + matSuffix + mat-icon-button + matTooltip="Click for GitLab git clone URL info" + href="https://docs.gitlab.com/ee/gitlab-basics/start-using-git.html#clone-with-https" + target="__blank" + color="primary" + > + <mat-icon aria-label="Info icon" fontIcon="info" /> + </a> + <mat-error> + Must be a valid URL ending in <code>.git</code> + </mat-error> + <mat-hint>The Git URL to the nshmp-haz repository</mat-hint> + </mat-form-field> + + <!-- NSHMP config: source code SHA --> + <mat-form-field class="grid-col-12 tablet:grid-col-6"> + <mat-label> + Source Code Branch, Tag, or Commit + <span class="form-required">*</span> + </mat-label> + <input + matInput + type="text" + [formControl]=" + form.controls.nshmpConfig.controls.sourceCodeSha + " + /> + <span matPrefix> + <mat-icon aria-label="Code icon" fontIcon="code" /> + </span> + <mat-hint> + The branch, tag, or commit of the nshmp-haz repository + </mat-hint> + <mat-error>Must not contain spaces</mat-error> + </mat-form-field> + + <!-- NSHMP config: class name --> + <mat-form-field class="grid-col-12 tablet:grid-col-6"> + <mat-label> + Class Name to Run<span class="form-required">*</span> + </mat-label> + <mat-select + [formControl]=" + form.controls.nshmpConfig.controls.className + " + > + @for (class of nshmpHazClasses; track class) { + <mat-option [value]="class"> + {{ class }} + </mat-option> } - <mat-hint - >The Git URL to the nshmp-haz repository</mat-hint - > - </mat-form-field> + </mat-select> + <span matPrefix> + <mat-icon aria-label="Code icon" fontIcon="code" /> + </span> + <a + matSuffix + mat-icon-button + matTooltip="Click for list of Java classes to run" + href="https://code.usgs.gov/ghsc/nshmp/nshmp-haz/-/tree/main/src/main/java/gov/usgs/earthquake/nshmp" + target="__blank" + color="primary" + > + <mat-icon aria-label="Info icon" fontIcon="info" /> + </a> + <mat-hint>Java class name of class to run</mat-hint> + </mat-form-field> - <!-- NSHMP config: source code SHA --> + <!-- NSHMP config: return period --> + @if ( + form.controls.nshmpConfig.value.className === + NshmpHazClass.DISAGG_CALC + ) { <mat-form-field class="grid-col-12 tablet:grid-col-6"> <mat-label> - Source Code Branch, Tag, or Commit - <span class="form-required">*</span> + Return Period for {{ NshmpHazClass.DISAGG_CALC }} + <span class="form-required"> * </span> </mat-label> <input matInput - type="text" - [ngrxFormControlState]=" - form.controls.nshmpConfig.controls.sourceCodeSha + [formControl]=" + form.controls.nshmpConfig.controls.returnPeriod " + type="number" + [min]="formBounds.returnPeriod.min" + [max]="formBounds.returnPeriod.max" + step="100" /> - <span matPrefix> - <mat-icon aria-label="Code icon" fontIcon="code" /> - </span> <mat-hint> - The branch, tag, or commit of the nshmp-haz repository + The return period of interest for + {{ NshmpHazClass.DISAGG_CALC }} + </mat-hint> + <mat-hint align="end"> + [ + {{ formBounds.returnPeriod.min }}, + {{ formBounds.returnPeriod.max }} + ] </mat-hint> - <mat-error>Must not contain spaces</mat-error> </mat-form-field> + } - <!-- NSHMP config: class name --> - <mat-form-field class="grid-col-12 tablet:grid-col-6"> - <mat-label> - Class Name to Run<span class="form-required">*</span> - </mat-label> - <mat-select - [ngrxFormControlState]=" - form.controls.nshmpConfig.controls.className - " - > - @for (class of nshmpHazClasses; track class) { - <mat-option [value]="class"> - {{ class }} - </mat-option> - } - </mat-select> - <span matPrefix> - <mat-icon aria-label="Code icon" fontIcon="code" /> - </span> - <a - matSuffix - mat-icon-button - matTooltip="Click for list of Java classes to run" - href="https://code.usgs.gov/ghsc/nshmp/nshmp-haz/-/tree/main/src/main/java/gov/usgs/earthquake/nshmp" - target="__blank" + <!-- NSHMP config: nshmp-lib --> + <div class="settings-subsection margin-top-1"> + <mat-label class="settings-subsection--label"> + <mat-slide-toggle + [formControl]="form.controls.overrideNshmpLib" color="primary" + class="lib-toggle" > - <mat-icon aria-label="Info icon" fontIcon="info" /> - </a> - <mat-hint>Java class name of class to run</mat-hint> - </mat-form-field> - - <!-- NSHMP config: return period --> - @if ( - form.controls.nshmpConfig.value.className === - NshmpHazClass.DISAGG_CALC - ) { - <mat-form-field class="grid-col-12"> + Provide nshmp-lib Dependency + </mat-slide-toggle> + </mat-label> + <div class="settings-subsection--section"> + <!-- NSHMP config: nshmp-lib Git URL --> + <mat-form-field class="grid-col-12 tablet:grid-col-8"> <mat-label> - Return Period for {{ NshmpHazClass.DISAGG_CALC }} - @if ( - form.controls.nshmpConfig.value.className === - NshmpHazClass.DISAGG_CALC - ) { + nshmp-lib Git URL + @if (form.value.overrideNshmpLib) { <span class="form-required"> * </span> } </mat-label> <input matInput - [ngrxFormControlState]=" - form.controls.nshmpConfig.controls.returnPeriod + type="text" + [formControl]=" + form.controls.nshmpConfig.controls.nshmpLibGitUrl " - [disabled]=" - form.controls.nshmpConfig.controls.returnPeriod - .isDisabled - " - type="number" - [min]="formBounds.returnPeriod.min" - [max]="formBounds.returnPeriod.max" - step="100" /> - <mat-hint> - The return period of interest for - {{ NshmpHazClass.DISAGG_CALC }} - </mat-hint> - <mat-hint align="end"> - [ - {{ formBounds.returnPeriod.min }}, - {{ formBounds.returnPeriod.max }} - ] - </mat-hint> - </mat-form-field> - } - - <!-- NSHMP config: nshmp-lib --> - <div class="settings-subsection margin-top-1"> - <mat-label class="settings-subsection--label"> - <mat-slide-toggle - [ngrxFormControlState]=" - form.controls.overrideNshmpLib - " + <span matPrefix> + <mat-icon aria-label="Code icon" fontIcon="code" /> + </span> + <a + matSuffix + mat-icon-button + matTooltip="Click for GitLab git clone URL info" + href="https://docs.gitlab.com/ee/gitlab-basics/start-using-git.html#clone-with-https" + target="__blank" color="primary" - class="lib-toggle" > - Provide nshmp-lib Dependency - </mat-slide-toggle> - </mat-label> - <div class="settings-subsection--section"> - <!-- NSHMP config: nshmp-lib Git URL --> - <mat-form-field class="grid-col-12 tablet:grid-col-8"> - <mat-label> - nshmp-lib Git URL - @if (form.value.overrideNshmpLib) { - <span class="form-required"> * </span> - } - </mat-label> - <input - matInput - type="text" - [ngrxFormControlState]=" - form.controls.nshmpConfig.controls.nshmpLibGitUrl - " - [disabled]=" - form.controls.nshmpConfig.controls.nshmpLibGitUrl - .isDisabled - " - /> - <span matPrefix> - <mat-icon aria-label="Code icon" fontIcon="code" /> - </span> - <a - matSuffix - mat-icon-button - matTooltip="Click for GitLab git clone URL info" - href="https://docs.gitlab.com/ee/gitlab-basics/start-using-git.html#clone-with-https" - target="__blank" - color="primary" - > - <mat-icon aria-label="Info icon" fontIcon="info" /> - </a> - @if ( - (form$ | async)?.errors?._nshmpConfig - ?._nshmpLibGitUrl?.pattern?.pattern === whitespace - ) { - <mat-error> Must not contain spaces </mat-error> - } @else { - <mat-error> - Must be a valid URL ending in <code>.git</code> - </mat-error> - } - <mat-hint - >The Git URL to the nshmp-lib repository</mat-hint - > - </mat-form-field> - - <!-- NSHMP config: nshmp-lib source code SHA --> - <mat-form-field - class="grid-col-12 tablet:grid-col-4 margin-bottom-1" + <mat-icon aria-label="Info icon" fontIcon="info" /> + </a> + <mat-error> + Must be a valid URL ending in <code>.git</code> + </mat-error> + <mat-hint + >The Git URL to the nshmp-lib repository</mat-hint > - <mat-label> - nshmp-lib Branch, Tag, or Commit - @if (form.value.overrideNshmpLib) { - <span class="form-required"> * </span> - } - </mat-label> - <input - matInput - type="text" - [ngrxFormControlState]=" - form.controls.nshmpConfig.controls.nshmpLibSha - " - [disabled]=" - form.controls.nshmpConfig.controls.nshmpLibSha - .isDisabled - " - /> - <span matPrefix> - <mat-icon aria-label="Code icon" fontIcon="code" /> - </span> - @if ( - (form$ | async)?.errors?._nshmpConfig?._nshmpLibSha - ?.pattern?.pattern === whitespace - ) { - <mat-error> Must not contain spaces </mat-error> - } @else { - <mat-error> - Must be a valid URL ending in <code>.git</code> - </mat-error> - } - <mat-hint> - The branch, tag, or commit of the nshmp-lib - repository - </mat-hint> - </mat-form-field> - </div> - </div> - </div> - </div> - - <mat-divider /> + </mat-form-field> - <div class="settings-subsection"> - <mat-label class="settings-subsection--label"> - National Seismic Hazard Model - </mat-label> - <div class="settings-subsection--section"> - <!-- NSHMP config: model Git URL --> - <mat-form-field class="grid-col-12"> - <mat-label> - National Seismic Hazard Model Git URL - <span class="form-required">*</span> - </mat-label> - <input - matInput - type="text" - [ngrxFormControlState]=" - form.controls.nshmpConfig.controls.modelGitUrl - " - /> - <span matPrefix> - <mat-icon - aria-label="Plot icon" - fontIcon="show_chart" - /> - </span> - <a - matSuffix - mat-icon-button - matTooltip="Click for GitLab URL info" - href="https://docs.gitlab.com/ee/gitlab-basics/start-using-git.html#clone-with-https" - target="__blank" - color="primary" + <!-- NSHMP config: nshmp-lib source code SHA --> + <mat-form-field + class="grid-col-12 tablet:grid-col-4 margin-bottom-1" > - <mat-icon aria-label="Info icon" fontIcon="info" /> - </a> - <mat-hint>The Git URL to the NSHM repository</mat-hint> - @if ( - (form$ | async)?.errors?._nshmpConfig?._modelGitUrl - ?.pattern?.pattern === whitespace - ) { - <mat-error> Must not contain spaces </mat-error> - } @else { + <mat-label> + nshmp-lib Branch, Tag, or Commit + @if (form.value.overrideNshmpLib) { + <span class="form-required"> * </span> + } + </mat-label> + <input + matInput + type="text" + [formControl]=" + form.controls.nshmpConfig.controls.nshmpLibSha + " + /> + <span matPrefix> + <mat-icon aria-label="Code icon" fontIcon="code" /> + </span> <mat-error> Must be a valid URL ending in <code>.git</code> </mat-error> - } - </mat-form-field> - - <!-- NSHMP config: model SHA --> - <mat-form-field class="grid-col-12 tablet:grid-col-6"> - <mat-label> - Model Branch, Tag, or Commit - <span class="form-required">*</span> - </mat-label> - <input - matInput - type="text" - [ngrxFormControlState]=" - form.controls.nshmpConfig.controls.modelSha - " - /> - <span matPrefix> - <mat-icon aria-label="Code icon" fontIcon="code" - >code</mat-icon - > - </span> - <mat-error>Must not contain spaces</mat-error> - <mat-hint> - The branch, tag, or commit of the NSHM repository - </mat-hint> - </mat-form-field> - - <!-- NSHMP config: model path --> - <mat-form-field - class="grid-col-12 tablet:grid-col-6 margin-bottom-1" - > - <mat-label>NSHM Path Inside Tarball</mat-label> - <input - matInput - type="text" - [ngrxFormControlState]=" - form.controls.nshmpConfig.controls.modelPath - " - /> - <span matPrefix> - <mat-icon aria-label="Folder icon" fontIcon="folder" /> - </span> - <mat-error>Must not contain spaces</mat-error> - <mat-hint>Path inside tarball to model</mat-hint> - </mat-form-field> + <mat-hint> + The branch, tag, or commit of the nshmp-lib repository + </mat-hint> + </mat-form-field> + </div> </div> </div> + </div> - <mat-divider /> - - <!-- NSHMP config: site file --> - <div class="settings-subsection padding-top-1"> - <mat-label class="settings-subsection--label" - >Site File</mat-label - > - <div class="settings-subsection--section"> - <div class="grid-col-12 padding-top-1"> - Upload CSV or GeoJSON - <a - href="https://code.usgs.gov/ghsc/nshmp/nshmp-haz/-/blob/main/docs/pages/Site-Specification.md" - target="__blank" + <mat-divider /> + + <div class="settings-subsection"> + <mat-label class="settings-subsection--label"> + National Seismic Hazard Model + </mat-label> + <div class="settings-subsection--section"> + <!-- NSHMP config: model Git URL --> + <mat-form-field class="grid-col-12"> + <mat-label> + National Seismic Hazard Model Git URL + <span class="form-required">*</span> + </mat-label> + <input + matInput + type="text" + [formControl]=" + form.controls.nshmpConfig.controls.modelGitUrl + " + /> + <span matPrefix> + <mat-icon aria-label="Plot icon" fontIcon="show_chart" /> + </span> + <a + matSuffix + mat-icon-button + matTooltip="Click for GitLab URL info" + href="https://docs.gitlab.com/ee/gitlab-basics/start-using-git.html#clone-with-https" + target="__blank" + color="primary" + > + <mat-icon aria-label="Info icon" fontIcon="info" /> + </a> + <mat-hint>The Git URL to the NSHM repository</mat-hint> + <mat-error> + Must be a valid URL ending in <code>.git</code> + </mat-error> + </mat-form-field> + + <!-- NSHMP config: model SHA --> + <mat-form-field class="grid-col-12 tablet:grid-col-6"> + <mat-label> + Model Branch, Tag, or Commit + <span class="form-required">*</span> + </mat-label> + <input + matInput + type="text" + [formControl]=" + form.controls.nshmpConfig.controls.modelSha + " + /> + <span matPrefix> + <mat-icon aria-label="Code icon" fontIcon="code" + >code</mat-icon > - Site File - </a> - <br /> - <input - #uploadSiteFile - class="padding-y-1" - type="file" - accept=".geojson,.csv" - (change)="importSiteFile()" - /> - </div> + </span> + <mat-error>Must not contain spaces</mat-error> + <mat-hint> + The branch, tag, or commit of the NSHM repository + </mat-hint> + </mat-form-field> + + <!-- NSHMP config: model path --> + <mat-form-field + class="grid-col-12 tablet:grid-col-6 margin-bottom-1" + > + <mat-label>NSHM Path Inside Tarball</mat-label> + <input + matInput + type="text" + [formControl]=" + form.controls.nshmpConfig.controls.modelPath + " + /> + <span matPrefix> + <mat-icon aria-label="Folder icon" fontIcon="folder" /> + </span> + <mat-error>Must not contain spaces</mat-error> + <mat-hint>Path inside tarball to model</mat-hint> + </mat-form-field> + </div> + </div> - <mat-form-field class="grid-col-12 padding-top-2"> - <mat-label> - URL to nshmp-haz Site File. - <span class="form-required">*</span> - </mat-label> - <input - matInput - [ngrxFormControlState]=" - form.controls.nshmpConfig.controls.siteFileUrl - " - /> - <span matPrefix> - <mat-icon aria-label="Note icon" fontIcon="note_add" /> - </span> - <a - matSuffix - mat-icon-button - matTooltip="Click for site file info" - href="https://code.usgs.gov/ghsc/nshmp/nshmp-haz/-/blob/main/docs/pages/Site-Specification.md" - target="__blank" - color="primary" - > - <mat-icon aria-label="Info icon" fontIcon="info" /> - </a> - @if ( - (form$ | async)?.errors?._nshmpConfig?._siteFileUrl - ?.pattern?.pattern === whitespace - ) { - <mat-error> Must not contain spaces </mat-error> - } @else { - <mat-error> Must be a valid URL </mat-error> - } - <mat-hint - >The URL to a GeoJSON or CSV file to run with</mat-hint - > - </mat-form-field> + <mat-divider /> + + <!-- NSHMP config: site file --> + <div class="settings-subsection padding-top-1"> + <mat-label class="settings-subsection--label" + >Site File</mat-label + > + <div class="settings-subsection--section"> + <div class="grid-col-12 padding-top-1"> + Upload CSV or GeoJSON + <a + href="https://code.usgs.gov/ghsc/nshmp/nshmp-haz/-/blob/main/docs/pages/Site-Specification.md" + target="__blank" + > + Site File + </a> + <br /> + <input + #uploadSiteFileEl + class="padding-y-1" + type="file" + accept=".geojson,.csv" + (change)="importSiteFile()" + /> </div> + + <mat-form-field class="grid-col-12 padding-top-2"> + <mat-label> + URL to nshmp-haz Site File. + <span class="form-required">*</span> + </mat-label> + <input + matInput + [formControl]=" + form.controls.nshmpConfig.controls.siteFileUrl + " + /> + <span matPrefix> + <mat-icon aria-label="Note icon" fontIcon="note_add" /> + </span> + <a + matSuffix + mat-icon-button + matTooltip="Click for site file info" + href="https://code.usgs.gov/ghsc/nshmp/nshmp-haz/-/blob/main/docs/pages/Site-Specification.md" + target="__blank" + color="primary" + > + <mat-icon aria-label="Info icon" fontIcon="info" /> + </a> + <mat-error> Must be a valid URL </mat-error> + <mat-hint + >The URL to a GeoJSON or CSV file to run with</mat-hint + > + </mat-form-field> </div> </div> </div> - </mat-expansion-panel> - - <!-- Map config --> - <mat-expansion-panel expanded> - <mat-expansion-panel-header> - <mat-panel-title>GMT Map Configuration</mat-panel-title> - </mat-expansion-panel-header> - - <mat-divider /> - - <div class="settings-subsection"> - <div class="settings-subsection--section"> - <!-- Map config: Title --> - <mat-form-field class="grid-col-12"> - <mat-label> Title (Optional)</mat-label> - <input - matInput - type="text" - [ngrxFormControlState]=" - form.controls.mapConfig.controls.title - " - /> - <mat-hint>First row of GMT hazard map title</mat-hint> - </mat-form-field> - - <!-- Map config: Region --> - <mat-form-field class="grid-col-12 margin-bottom-neg-1"> - <mat-label> Region (Optional)</mat-label> - <mat-select - [ngrxFormControlState]=" - form.controls.mapConfig.controls.region - " - > - @for (keyValue of mapRegions; track keyValue) { - <mat-option [value]="keyValue.value"> - {{ keyValue.key }} - </mat-option> - } - </mat-select> - <mat-hint>Region bounds, default is based on data</mat-hint> - </mat-form-field> - </div> + </div> + </mat-expansion-panel> + + <!-- Map config --> + <mat-expansion-panel expanded> + <mat-expansion-panel-header> + <mat-panel-title>GMT Map Configuration</mat-panel-title> + </mat-expansion-panel-header> + + <mat-divider /> + + <div class="settings-subsection"> + <div class="settings-subsection--section"> + <!-- Map config: Title --> + <mat-form-field class="grid-col-12"> + <mat-label> Title (Optional)</mat-label> + <input + matInput + type="text" + [formControl]="form.controls.mapConfig.controls.title" + /> + <mat-hint>First row of GMT hazard map title</mat-hint> + </mat-form-field> + + <!-- Map config: Region --> + <mat-form-field class="grid-col-12 margin-bottom-neg-1"> + <mat-label> Region (Optional)</mat-label> + <mat-select + [formControl]="form.controls.mapConfig.controls.region" + > + @for (keyValue of mapRegions; track keyValue) { + <mat-option [value]="keyValue.value"> + {{ keyValue.key }} + </mat-option> + } + </mat-select> + <mat-hint>Region bounds, default is based on data</mat-hint> + </mat-form-field> </div> - </mat-expansion-panel> - - <!-- Calc Config section --> - <mat-expansion-panel expanded> - <mat-expansion-panel-header> - <mat-panel-title>Calc Configuration</mat-panel-title> - </mat-expansion-panel-header> - - <mat-divider /> - - <div class="settings-subsection program-section"> - <div class="settings-subsection--section"> - <!-- Calc config: config file --> - <div class="settings-subsection padding-top-1"> - <mat-label class="settings-subsection--label"> - Calculation Configuration File - </mat-label> - - <div class="settings-subsection--section padding-top-1"> - <div class="grid-col-12"> - Upload nshmp-haz - <a - href="https://code.usgs.gov/ghsc/nshmp/nshmp-haz/-/blob/main/docs/pages/Calculation-Configuration.md" - target="__blank" - > - Calculation Configuration File - </a> - <br /> - <input - #calcConfig - class="padding-y-1" - type="file" - accept=".json" - (change)="importCalcConfigFile()" - /> - </div> + </div> + </mat-expansion-panel> + + <!-- Calc Config section --> + <mat-expansion-panel expanded> + <mat-expansion-panel-header> + <mat-panel-title>Calc Configuration</mat-panel-title> + </mat-expansion-panel-header> + + <mat-divider /> + + <div class="settings-subsection program-section"> + <div class="settings-subsection--section"> + <!-- Calc config: config file --> + <div class="settings-subsection padding-top-1"> + <mat-label class="settings-subsection--label"> + Calculation Configuration File + </mat-label> + + <div class="settings-subsection--section padding-top-1"> + <div class="grid-col-12"> + Upload nshmp-haz + <a + href="https://code.usgs.gov/ghsc/nshmp/nshmp-haz/-/blob/main/docs/pages/Calculation-Configuration.md" + target="__blank" + > + Calculation Configuration File + </a> + <br /> + <input + #calcConfigEl + class="padding-y-1" + type="file" + accept=".json" + (change)="importCalcConfigFile()" + /> + </div> - <div class="grid-col-12 padding-y-2"> - <mat-expansion-panel - [disabled]="(calcConfig$ | async) === null" - > - <mat-expansion-panel-header> - <mat-panel-title - >Calculation Configuration</mat-panel-title - > - <mat-panel-description> - Imported configuration - </mat-panel-description> - </mat-expansion-panel-header> - - <div> - <pre class="code-block"> + <div class="grid-col-12 padding-y-2"> + <mat-expansion-panel + [disabled]="calcConfig() === null" + [expanded]="calcConfig() !== null" + > + <mat-expansion-panel-header> + <mat-panel-title + >Calculation Configuration</mat-panel-title + > + <mat-panel-description> + Imported configuration + </mat-panel-description> + </mat-expansion-panel-header> + + <div> + <pre class="code-block"> <code> - {{ calcConfigJson(calcConfig$ | async) }} + {{ calcConfigJson() }} </code> </pre> - </div> - </mat-expansion-panel> - </div> + </div> + </mat-expansion-panel> </div> </div> </div> </div> - </mat-expansion-panel> - </mat-accordion> - - <mat-divider /> - - <!-- Buttons --> - <div class="padding-y-2 grid-col-12"> - <button - mat-raised-button - color="primary" - type="submit" - [disabled]="form.isInvalid" - > - Submit Job - </button> - <button - class="float-right" - mat-raised-button - color="warn" - type="reset" - (click)="facade.resetForm()" - [disabled]="form.isPristine" - > - Reset - </button> - </div> - </form> - </nshmp-template-form-fields> - </div> -} + </div> + </mat-expansion-panel> + </mat-accordion> + + <mat-divider /> + + <!-- Buttons --> + <div class="padding-y-2 grid-col-12"> + <button + mat-raised-button + color="primary" + type="submit" + [disabled]="form.invalid" + > + Submit Job + </button> + <button + class="float-right" + mat-raised-button + color="warn" + type="reset" + (click)="facade.resetForm()" + [disabled]="form.pristine" + > + Reset + </button> + </div> + </form> + </nshmp-template-form-fields> +</div> diff --git a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/form/form.component.ts b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/form/form.component.ts index fde4265e7acb7a2546adf7733c7c427ffcc471d0..cdc5e04d9df34db35a81b4dcd75777c34a3aeee0 100644 --- a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/form/form.component.ts +++ b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/form/form.component.ts @@ -1,12 +1,14 @@ import {AsyncPipe} from '@angular/common'; import { Component, + effect, ElementRef, Input, OnDestroy, OnInit, ViewChild, } from '@angular/core'; +import {ReactiveFormsModule} from '@angular/forms'; import {MatButton, MatIconAnchor} from '@angular/material/button'; import {MatOption} from '@angular/material/core'; import {MatDialog} from '@angular/material/dialog'; @@ -26,14 +28,13 @@ import { MatPrefix, MatSuffix, } from '@angular/material/form-field'; +import {MatIcon} from '@angular/material/icon'; import {MatInput} from '@angular/material/input'; import {MatSelect} from '@angular/material/select'; import {MatSlideToggle} from '@angular/material/slide-toggle'; import {MatTab} from '@angular/material/tabs'; import {MatTooltip} from '@angular/material/tooltip'; -import {NshmpNgrxFormsModule} from '@ghsc/nshmp-lib-ng/nshmp'; import {NshmpTemplateFormFieldsComponent} from '@ghsc/nshmp-template'; -import {CalcConfig} from '@ghsc/nshmp-utils-ts/libs/aws/run-nshmp-haz'; import {Status} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws-utils'; import {Subscription} from 'rxjs'; import * as YAML from 'yaml'; @@ -73,7 +74,8 @@ import {JobSubmittedComponent} from '../job-submitted/job-submitted.component'; MatButton, AsyncPipe, NshmpTemplateFormFieldsComponent, - NshmpNgrxFormsModule, + ReactiveFormsModule, + MatIcon, ], selector: 'app-form', standalone: true, @@ -94,23 +96,21 @@ export class FormComponent implements OnInit, OnDestroy { yamlTab: MatTab; /** The element reference for the calculation configuration input element */ - @ViewChild('calcConfig') + @ViewChild('calcConfigEl') calcConfigEl: ElementRef<HTMLInputElement>; /** The element reference for the configuration input element */ - @ViewChild('config') + @ViewChild('configEl') configEl: ElementRef<HTMLInputElement>; /** The element reference to the upload site file input */ - @ViewChild('uploadSiteFile') + @ViewChild('uploadSiteFileEl') uploadSiteEl: ElementRef<HTMLInputElement>; /** Common EC2 instance types */ commonInstances = commonInstances(); /** Map region for GMT bounds */ mapRegions = mapRegions(); - /** The submit hazard job service response subscription */ - responseSubscription: Subscription; /** Form bounds */ formBounds = formBounds; /** nshmp-haz Java classes to run */ @@ -119,30 +119,64 @@ export class FormComponent implements OnInit, OnDestroy { nshmpHazClasses = Object.values(NshmpHazClass); /** Whitespace reqex */ whitespace = '/^\\S+$/'; + /** Whether the reset button is disabled */ + resetDisabled = false; /** Calculation configuration state */ - calcConfig$ = this.facade.calcConfig$; + calcConfig = this.facade.calcConfig; /** Control form state */ - form$ = this.facade.form$; + form = this.facade.formGroup; + + private classNameSubscription = new Subscription(); + private overrideSubscription = new Subscription(); constructor( public facade: AppFacade, private matDialog: MatDialog, public appService: AppService - ) {} + ) { + effect(() => { + const response = this.facade.state().serviceResponse; - ngOnInit() { - this.responseSubscription = this.facade.serviceResponse$.subscribe( - response => { - if (response && response.status === Status.SUCCESS) { - this.matDialog.open(JobSubmittedComponent); - } + if (response && response.status === Status.SUCCESS) { + this.matDialog.open(JobSubmittedComponent); } - ); + }); + } + + ngOnInit(): void { + const {nshmpConfig} = this.form.controls; + + this.classNameSubscription = + nshmpConfig.controls.className.valueChanges.subscribe(className => { + if (className === NshmpHazClass.DISAGG_CALC.toString()) { + nshmpConfig.controls.returnPeriod.enable(); + } else { + nshmpConfig.controls.returnPeriod.disable(); + } + }); + + this.overrideSubscription = + this.form.controls.overrideNshmpLib.valueChanges.subscribe( + overrideNshmpLib => { + if (overrideNshmpLib) { + nshmpConfig.controls.nshmpLibGitUrl.enable(); + nshmpConfig.controls.nshmpLibSha.enable(); + } else { + this.form.controls.nshmpConfig.controls.nshmpLibGitUrl.patchValue( + null + ); + nshmpConfig.controls.nshmpLibGitUrl.disable(); + nshmpConfig.controls.nshmpLibSha.patchValue(null); + nshmpConfig.controls.nshmpLibSha.disable(); + } + } + ); } ngOnDestroy(): void { - this.responseSubscription.unsubscribe(); + this.classNameSubscription.unsubscribe(); + this.overrideSubscription.unsubscribe(); } /** @@ -151,8 +185,8 @@ export class FormComponent implements OnInit, OnDestroy { * @param calcConfig The calculation configuration * @returns */ - calcConfigJson(calcConfig: CalcConfig): string { - return `\n${YAML.stringify(calcConfig, {indent: 2})}`; + calcConfigJson(): string { + return `\n${YAML.stringify(this.calcConfig(), {indent: 2})}`; } /** diff --git a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/job-submitted/job-submitted.component.html b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/job-submitted/job-submitted.component.html index 56dc5677ae8e6d280f3906488fbdc1a8559b5a6f..2cb89a8ee80bfb7816fcbe771337201fdbc1704c 100644 --- a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/job-submitted/job-submitted.component.html +++ b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/job-submitted/job-submitted.component.html @@ -1,21 +1,20 @@ <h1 mat-dialog-title>Job Submitted</h1> <div mat-dialog-content> - <div>Instance ID: {{ (serviceResponse$ | async)?.response?.instanceId }}</div> - <div>Job ID: {{ (serviceResponse$ | async)?.response?.jobId }}</div> + <div>Job ID: {{ serviceResponse()?.response?.jobId }}</div> <br /> <div> Configuration: <pre class="code-block"> <code> - {{ request$ | async | yaml }} + {{ request() | yaml }} </code> </pre> </div> </div> <div mat-dialog-actions> - @if ((serviceResponse$ | async)?.response; as response) { + @if (serviceResponse()?.response; as response) { <button mat-raised-button color="primary" (click)="checkJob(response)"> Check on Job </button> diff --git a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/job-submitted/job-submitted.component.ts b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/job-submitted/job-submitted.component.ts index 8be1d223ee447ff5fc0c23c686696ef1006008a5..567a35185f2b6792d540495b2d5f3df3b96fce75 100644 --- a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/job-submitted/job-submitted.component.ts +++ b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/components/job-submitted/job-submitted.component.ts @@ -1,6 +1,6 @@ import {CdkScrollable} from '@angular/cdk/scrolling'; import {AsyncPipe, Location} from '@angular/common'; -import {Component} from '@angular/core'; +import {Component, computed} from '@angular/core'; import {MatButton} from '@angular/material/button'; import { MatDialogActions, @@ -9,7 +9,7 @@ import { MatDialogTitle, } from '@angular/material/dialog'; import {Router} from '@angular/router'; -import {YamlPipe} from '@ghsc/nshmp-lib-ng/aws'; +import {YamlPipe} from '@ghsc/nshmp-lib-no-ngrx/aws'; import {RunNshmpHazResponseData} from '@ghsc/nshmp-utils-ts/libs/aws/run-nshmp-haz'; import {devApps} from 'projects/nshmp-apps/src/shared/utils/applications.utils'; @@ -35,8 +35,8 @@ import {AppFacade} from '../../state/app.facade'; templateUrl: './job-submitted.component.html', }) export class JobSubmittedComponent { - serviceResponse$ = this.facade.serviceResponse$; - request$ = this.facade.serviceResponse$; + serviceResponse = this.facade.serviceResponse; + request = computed(() => this.facade.serviceResponse()?.request); constructor( private facade: AppFacade, diff --git a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/models/form-group.model.ts b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/models/form-group.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ed6087acb0d108862f70a4999eed969eb94a3d6 --- /dev/null +++ b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/models/form-group.model.ts @@ -0,0 +1,14 @@ +import {FormControl} from '@angular/forms'; +import {FormGroupControls} from '@ghsc/nshmp-lib-no-ngrx/nshmp'; +import { + CloudConfig, + MapConfig, + NshmpConfig, +} from '@ghsc/nshmp-utils-ts/libs/aws/run-nshmp-haz'; + +export interface RunNshmpHazFormGroup { + cloudConfig: FormGroupControls<CloudConfig>; + mapConfig: FormGroupControls<MapConfig>; + nshmpConfig: FormGroupControls<NshmpConfig>; + overrideNshmpLib: FormControl<boolean>; +} diff --git a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.actions.ts b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.actions.ts deleted file mode 100644 index 43cae35c647406911f5f1a2553389d49ea29e562..0000000000000000000000000000000000000000 --- a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.actions.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { - CalcConfig, - RunNshmpHazHttpPostConfig, - RunNshmpHazResponseData, -} from '@ghsc/nshmp-utils-ts/libs/aws/run-nshmp-haz'; -import {Response} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws-utils'; -import {createActionGroup, emptyProps, props} from '@ngrx/store'; - -import {FileInfo} from '../models/file-info.model'; - -export const actions = createActionGroup({ - events: { - 'Call Service': emptyProps(), - 'Check Before Call': emptyProps(), - /** NGRX action to get latest NSHM tag for nshm-conus */ - 'Get Nshm Tag': emptyProps(), - /** NGRX action to import the calculation configuration file */ - 'Import Calc Config File': props<{calcConfig: CalcConfig}>(), - /** NGRX action to import the configuration file */ - 'Import Config File': props<{config: RunNshmpHazHttpPostConfig}>(), - /** NGRX action to reset the form fields */ - 'Reset Form': emptyProps(), - /** NGRX action for the service response */ - 'Service Response': props<{ - serviceResponse: Response< - RunNshmpHazHttpPostConfig, - RunNshmpHazResponseData - >; - }>(), - /** NGRX action to upload files */ - 'Upload Files': props<{fileInfo: FileInfo}>(), - }, - source: 'Submit nshmp-haz Jobs to AWS Development App', -}); diff --git a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.effects.ts b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.effects.ts deleted file mode 100644 index 8737bef224c1b1067437fe472daff60c43a06953..0000000000000000000000000000000000000000 --- a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.effects.ts +++ /dev/null @@ -1,215 +0,0 @@ -import {HttpClient} from '@angular/common/http'; -import {Injectable} from '@angular/core'; -import {NshmpService, SpinnerService} from '@ghsc/nshmp-lib-ng/nshmp'; -import { - RunNshmpHazHttpPostConfig, - RunNshmpHazResponseData, -} from '@ghsc/nshmp-utils-ts/libs/aws/run-nshmp-haz'; -import {Response} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws-utils'; -import {Actions, createEffect, ofType} from '@ngrx/effects'; -import {concatLatestFrom} from '@ngrx/operators'; -import {select, Store} from '@ngrx/store'; -import {MarkAsDirtyAction, SetValueAction} from 'ngrx-forms'; -import {environment} from 'projects/nshmp-apps/src/environments/environment'; -import {catchError, exhaustMap, map, mergeMap} from 'rxjs/operators'; - -import {FileType} from '../models/file-type.model'; -import { - UploadFileRequestData, - UploadFileResponseData, -} from '../models/file-upload.model'; -import {GitlabTagItem} from '../models/gitlab-tag-item.model'; -import {DEFAULT_FORM_VALUES} from '../utils/app.default-values'; -import {actions} from './app.actions'; -import {submitHazJobsAppFeature} from './app.reducer'; - -/** - * Application NGRX effects. - */ -@Injectable() -export class SubmitHazJobsAppEffects { - baseUrl = environment.webServices.aws.url; - - /** - * NGRX effect to call HTTP POST to run hazard jobs service. - */ - callService$ = createEffect(() => - this.actions$.pipe( - ofType(actions.callService), - concatLatestFrom(() => - this.store.select(submitHazJobsAppFeature.selectSubmitHazJobsState) - ), - exhaustMap(([, state]) => { - this.spinnerService.show('Calling nshmp-haz on AWS'); - const url = `${this.baseUrl}${environment.webServices.aws.services.runHazardJobs}`; - const {cloudConfig, mapConfig, nshmpConfig} = state.form.value; - - const postConfig: RunNshmpHazHttpPostConfig = { - calcConfig: { - ...state.calcConfig, - }, - cloudConfig: { - ...cloudConfig, - }, - mapConfig: { - ...mapConfig, - }, - nshmpConfig: { - ...nshmpConfig, - }, - }; - return this.nshmpService - .callService$(url, 'POST', JSON.stringify(postConfig)) - .pipe( - map( - ( - serviceResponse: Response< - RunNshmpHazHttpPostConfig, - RunNshmpHazResponseData - > - ) => { - this.spinnerService.remove(); - return actions.serviceResponse({serviceResponse}); - }, - catchError((error: Error) => this.nshmpService.throwError$(error)) - ) - ); - }), - catchError((error: Error) => this.nshmpService.throwError$(error)) - ) - ); - - /** - * NGRX effect to check site file is legit. - */ - checkFiles$ = createEffect(() => - this.actions$.pipe( - ofType(actions.checkBeforeCall), - concatLatestFrom(() => - this.store.select(submitHazJobsAppFeature.selectForm) - ), - exhaustMap(([, form]) => { - this.spinnerService.show('Checking files'); - const siteFile = form.value.nshmpConfig.siteFileUrl; - - return this.http.get(siteFile).pipe( - map(() => actions.callService()), - catchError((error: Error) => this.nshmpService.throwError$(error)) - ); - }), - catchError((error: Error) => this.nshmpService.throwError$(error)) - ) - ); - - /** - * NGRX effect to call GitLab to get latest tag of nshmp-conus repo. - */ - getNshmTag$ = createEffect(() => - this.actions$.pipe( - ofType(actions.getNshmTag), - concatLatestFrom(() => - this.store.pipe(select(submitHazJobsAppFeature.selectForm)) - ), - exhaustMap(([, form]) => { - const repo = 'ghsc%2Fnshmp%2Fnshms%2Fnshm-conus'; - const url = `https://code.usgs.gov/api/v4/projects/${repo}/repository/tags`; - - return this.http.get(url).pipe( - map((response: GitlabTagItem[]) => { - const tag = - response - ?.sort( - (a, b) => - new Date(a.authored_date).getMilliseconds() - - new Date(b.authored_date).getMilliseconds() - ) - .shift()?.name ?? - DEFAULT_FORM_VALUES.nshmpConfig.modelSha ?? - ''; - - return new SetValueAction( - form.controls.nshmpConfig.controls.modelSha.id, - tag - ); - }), - catchError((error: Error) => this.nshmpService.throwError$(error)) - ); - }), - catchError((error: Error) => this.nshmpService.throwError$(error)) - ) - ); - - /** - * NGRX effect to upload files to S3 using a pre-signed URL. - */ - uploadFiles$ = createEffect(() => - this.actions$.pipe( - ofType(actions.uploadFiles), - concatLatestFrom(() => - this.store.select(submitHazJobsAppFeature.selectForm) - ), - exhaustMap(([action, form]) => { - this.spinnerService.show('Getting pre-signed S3 URL'); - const fileInfo = action.fileInfo; - const service = environment.webServices.aws.services.uploadInputFile; - const url = `${this.baseUrl}${service}/${fileInfo.fileName}`; - let downloadUrl = ''; - - return this.nshmpService - .callService$(url) - .pipe( - mergeMap( - ( - serviceResponse: Response< - UploadFileRequestData, - UploadFileResponseData - > - ) => { - this.spinnerService.remove(); - this.spinnerService.show('Uploading file to S3'); - downloadUrl = serviceResponse.response.downloadUrl; - return this.http.put( - serviceResponse.response.preSignedUrl, - fileInfo.file - ); - } - ), - catchError((error: Error) => this.nshmpService.throwError$(error)) - ) - .pipe( - mergeMap(() => { - this.spinnerService.remove(); - let id = ''; - const {type} = fileInfo; - - switch (type) { - case FileType.SITE: { - id = form.controls.nshmpConfig.controls.siteFileUrl.id; - break; - } - default: { - return this.nshmpService.throwError$( - new Error(`Upload file type [${fileInfo.type}] not allowed`) - ); - } - } - return [ - new SetValueAction(id, downloadUrl), - new MarkAsDirtyAction(id), - ]; - }), - catchError((error: Error) => this.nshmpService.throwError$(error)) - ); - }), - catchError((error: Error) => this.nshmpService.throwError$(error)) - ) - ); - - constructor( - private actions$: Actions, - private http: HttpClient, - private nshmpService: NshmpService, - private spinnerService: SpinnerService, - private store: Store - ) {} -} diff --git a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.facade.ts b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.facade.ts index 096001069dcb778778b7ab13d3a9d2e70ec7dc46..02567f0b4b169e2d8e58f4f1d608916aa9d7204c 100644 --- a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.facade.ts +++ b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.facade.ts @@ -1,71 +1,125 @@ -import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; +import {computed, Injectable, Signal, signal} from '@angular/core'; +import {FormBuilder} from '@angular/forms'; import {NshmpService} from '@ghsc/nshmp-lib-ng/nshmp'; +import {SpinnerService} from '@ghsc/nshmp-lib-no-ngrx/nshmp'; import { CalcConfig, RunNshmpHazHttpPostConfig, RunNshmpHazResponseData, } from '@ghsc/nshmp-utils-ts/libs/aws/run-nshmp-haz'; import {Response} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws-utils'; -import {select, Store} from '@ngrx/store'; -import {FormGroupState} from 'ngrx-forms'; -import {Observable} from 'rxjs'; +import {environment} from 'projects/nshmp-apps/src/environments/environment'; +import {catchError, mergeMap} from 'rxjs'; import * as YAML from 'yaml'; import {FileInfo} from '../models/file-info.model'; import {FileType} from '../models/file-type.model'; +import { + UploadFileRequestData, + UploadFileResponseData, +} from '../models/file-upload.model'; +import {RunNshmpHazFormGroup} from '../models/form-group.model'; +import {GitlabTagItem} from '../models/gitlab-tag-item.model'; import {DEFAULT_FORM_VALUES} from '../utils/app.default-values'; -import {actions} from './app.actions'; -import {submitHazJobsAppFeature} from './app.reducer'; +import {addValidators} from '../utils/app-form.validators'; +import {AppState, INITIAL_STATE} from './app.state'; -/** - * Entrypoint for accessing NGRX store. - */ @Injectable({ providedIn: 'root', }) export class AppFacade { - constructor( - private store: Store, - private nshmpService: NshmpService - ) {} + /** Application state */ + readonly state = signal<AppState>(INITIAL_STATE); - /** - * Returns the caluclation configuration observable. - */ - get calcConfig$(): Observable<CalcConfig> { - return this.store.pipe(select(submitHazJobsAppFeature.selectCalcConfig)); - } + /** Form controls */ + readonly formGroup = this.formBuilder.group<RunNshmpHazFormGroup>({ + cloudConfig: this.formBuilder.group(DEFAULT_FORM_VALUES.cloudConfig), + mapConfig: this.formBuilder.group(DEFAULT_FORM_VALUES.mapConfig), + nshmpConfig: this.formBuilder.group(DEFAULT_FORM_VALUES.nshmpConfig), + overrideNshmpLib: this.formBuilder.control( + DEFAULT_FORM_VALUES.overrideNshmpLib + ), + }); - /** - * Returns the form fields state observable. - */ - get form$(): Observable<FormGroupState<RunNshmpHazHttpPostConfig>> { - return this.store.pipe(select(submitHazJobsAppFeature.selectForm)); + private baseUrl = environment.webServices.aws.url; + + constructor( + private formBuilder: FormBuilder, + private nshmpService: NshmpService, + private spinnerService: SpinnerService, + private http: HttpClient + ) { + addValidators(this.formGroup); + this.formGroup.controls.nshmpConfig.controls.nshmpLibGitUrl.disable(); + this.formGroup.controls.nshmpConfig.controls.nshmpLibSha.disable(); + this.formGroup.controls.nshmpConfig.controls.returnPeriod.disable(); } /** - * Returns the service response observable. + * Returns the caluclation configuration */ - get serviceResponse$(): Observable< - Response<RunNshmpHazHttpPostConfig, RunNshmpHazResponseData> - > { - return this.store.pipe( - select(submitHazJobsAppFeature.selectServiceResponse) - ); + get calcConfig(): Signal<CalcConfig> { + return computed(() => this.state().calcConfig); } /** - * Dispatch action to call service. + * Call service. */ callService(): void { - this.store.dispatch(actions.callService()); + this.spinnerService.show('Calling nshmp-haz on AWS'); + const url = `${this.baseUrl}${environment.webServices.aws.services.runHazardJobs}`; + const {cloudConfig, mapConfig, nshmpConfig} = this.formGroup.getRawValue(); + + const postConfig: RunNshmpHazHttpPostConfig = { + calcConfig: { + ...this.state().calcConfig, + }, + cloudConfig: { + ...cloudConfig, + }, + mapConfig: { + ...mapConfig, + }, + nshmpConfig: { + ...nshmpConfig, + }, + }; + + this.nshmpService + .callService$< + Response<RunNshmpHazHttpPostConfig, RunNshmpHazResponseData> + >(url, 'POST', JSON.stringify(postConfig)) + .pipe(catchError((error: Error) => this.nshmpService.throwError$(error))) + .subscribe(serviceResponse => + this.handleServiceResponse(serviceResponse) + ); } /** - * Dispatch action to call GitLab to get NSHM latest tag. + * Call GitLab to get NSHM latest tag. */ getNshmTag(): void { - this.store.dispatch(actions.getNshmTag()); + const repo = 'ghsc%2Fnshmp%2Fnshms%2Fnshm-conus'; + const url = `https://code.usgs.gov/api/v4/projects/${repo}/repository/tags`; + + this.http + .get(url) + .pipe(catchError((error: Error) => this.nshmpService.throwError$(error))) + .subscribe((response: GitlabTagItem[]) => { + const tag = + response + ?.sort( + (a, b) => + new Date(a.authored_date).getMilliseconds() - + new Date(b.authored_date).getMilliseconds() + ) + .shift()?.name ?? + DEFAULT_FORM_VALUES.nshmpConfig.modelSha ?? + ''; + + this.formGroup.controls.nshmpConfig.controls.modelSha.patchValue(tag); + }); } /** @@ -95,14 +149,24 @@ export class AppFacade { } /** - * Dispatch action to reset the form fields. + * Reset the form fields. */ resetForm(): void { - this.store.dispatch(actions.resetForm()); + this.formGroup.reset(DEFAULT_FORM_VALUES); + this.updateState({calcConfig: null}); } /** - * Dispatch action to upload files to S3. + * Returns the service response. + */ + get serviceResponse(): Signal< + Response<RunNshmpHazHttpPostConfig, RunNshmpHazResponseData> + > { + return computed(() => this.state().serviceResponse); + } + + /** + * Upload files to S3. * * @param files The files to upload * @param type The file type @@ -116,12 +180,79 @@ export class AppFacade { fileName: file.name, type, }; - this.store.dispatch(actions.uploadFiles({fileInfo})); + this.uploadFileToS3(fileInfo); }) .catch((error: Error) => this.nshmpService.throwError$(error)); } } + /** + * Handle service call response. + * + * @param serviceResponse The service response + */ + private handleServiceResponse( + serviceResponse: Response< + RunNshmpHazHttpPostConfig, + RunNshmpHazResponseData + > + ): void { + this.spinnerService.remove(); + this.updateState({serviceResponse}); + } + + /** + * Upload file to S3. + * + * @param fileInfo The file info + */ + private uploadFileToS3(fileInfo: FileInfo): void { + this.spinnerService.show('Getting pre-signed S3 URL'); + const service = environment.webServices.aws.services.uploadInputFile; + const url = `${this.baseUrl}${service}/${fileInfo.fileName}`; + let downloadUrl = ''; + + this.nshmpService + .callService$(url) + .pipe( + mergeMap( + ( + serviceResponse: Response< + UploadFileRequestData, + UploadFileResponseData + > + ) => { + this.spinnerService.remove(); + this.spinnerService.show('Uploading file to S3'); + downloadUrl = serviceResponse.response.downloadUrl; + return this.http.put( + serviceResponse.response.preSignedUrl, + fileInfo.file + ); + } + ), + catchError((error: Error) => this.nshmpService.throwError$(error)) + ) + .subscribe(() => { + this.spinnerService.remove(); + const {type} = fileInfo; + + switch (type) { + case FileType.SITE: { + this.formGroup.controls.nshmpConfig.controls.siteFileUrl.patchValue( + downloadUrl + ); + break; + } + default: { + return this.nshmpService.throwError$( + new Error(`Upload file type [${fileInfo.type}] not allowed`) + ); + } + } + }); + } + /** * Read a file. * @@ -145,7 +276,7 @@ export class AppFacade { } /** - * Read in calculation configuration and dispatch action to import file. + * Read in calculation configuration. * * @param content The JSON or YAML content * @param file The file @@ -165,7 +296,9 @@ export class AppFacade { throw new Error(`Type [${file.type}] not allowed`); } - this.store.dispatch(actions.importCalcConfigFile({calcConfig})); + this.updateState({ + calcConfig, + }); } catch (e) { const error = e instanceof Error ? e : new Error(e as string); this.nshmpService.throwError$(error); @@ -173,7 +306,7 @@ export class AppFacade { } /** - * Read in configuration and dispatch action to import configuration file. + * Read in configuration. * * @param content The JSON or YAML content * @param file The file @@ -215,10 +348,48 @@ export class AppFacade { }, }; - this.store.dispatch(actions.importConfigFile({config: awsConfig})); + this.formGroup.patchValue(awsConfig); + const overrideNshmpLib = + config?.nshmpConfig?.nshmpLibGitUrl || config?.nshmpConfig?.nshmpLibSha; + + if (overrideNshmpLib) { + this.formGroup.controls.nshmpConfig.controls.nshmpLibGitUrl.enable(); + this.formGroup.controls.nshmpConfig.controls.nshmpLibSha.enable(); + this.formGroup.controls.overrideNshmpLib.patchValue(true); + } else { + this.formGroup.controls.nshmpConfig.controls.nshmpLibGitUrl.disable(); + this.formGroup.controls.nshmpConfig.controls.nshmpLibGitUrl.patchValue( + null + ); + this.formGroup.controls.nshmpConfig.controls.nshmpLibSha.disable(); + this.formGroup.controls.nshmpConfig.controls.nshmpLibSha.patchValue( + null + ); + this.formGroup.controls.overrideNshmpLib.patchValue(false); + } + + if (awsConfig.calcConfig) { + this.updateState({ + calcConfig: awsConfig.calcConfig, + }); + } + + this.formGroup.markAsDirty(); } catch (e) { const error = e instanceof Error ? e : new Error(e as string); this.nshmpService.throwError$(error); } } + + /** + * Update state. + * + * @param state The state to update + */ + private updateState(state: Partial<AppState>): void { + this.state.set({ + ...this.state(), + ...state, + }); + } } diff --git a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.reducer.ts b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.reducer.ts deleted file mode 100644 index 7834a8632a5da028b94999a59ef6594a206a669e..0000000000000000000000000000000000000000 --- a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.reducer.ts +++ /dev/null @@ -1,157 +0,0 @@ -import {RunNshmpHazForm} from '@ghsc/nshmp-lib-ng/aws'; -import {NshmpConfig} from '@ghsc/nshmp-utils-ts/libs/aws/run-nshmp-haz'; -import {createFeature, createReducer, on} from '@ngrx/store'; -import { - disable, - enable, - formGroupReducer, - MarkAsDirtyAction, - MarkAsTouchedAction, - onNgrxForms, - onNgrxFormsAction, - ResetAction, - setValue, - SetValueAction, - updateGroup, - wrapReducerWithFormStateUpdate, -} from 'ngrx-forms'; - -import {NshmpHazClass} from '../models/nshmp-haz-class.model'; -import {DEFAULT_FORM_VALUES} from '../utils/app.default-values'; -import {validateForm} from '../utils/app-form.validators'; -import {actions} from './app.actions'; -import {FORM_ID, INITIAL_STATE} from './app.state'; - -/** - * Form field action keys - */ -const formKeys = { - className: `${FORM_ID}.nshmpConfig.className`, - overrideNshmpLib: `${FORM_ID}.overrideNshmpLib`, -}; - -export const submitHazJobsAppFeature = createFeature({ - name: 'submitHazJobs', - reducer: createReducer( - /** Initial state */ - INITIAL_STATE, - /** ngrx-forms reducer */ - onNgrxForms(), - /** Handle ngrx-form actions */ - onNgrxFormsAction(SetValueAction, (state, action) => { - switch (action.controlId) { - case formKeys.className: { - const form = updateGroup<RunNshmpHazForm>({ - nshmpConfig: updateGroup<NshmpConfig>({ - returnPeriod: - state.form.value.nshmpConfig.className === - NshmpHazClass.DISAGG_CALC.toString() - ? enable - : disable, - }), - })(state.form); - - return { - ...state, - form, - }; - } - case formKeys.overrideNshmpLib: { - const form = updateGroup<RunNshmpHazForm>({ - nshmpConfig: updateGroup<NshmpConfig>({ - nshmpLibGitUrl: state.form.value.overrideNshmpLib - ? enable - : control => disable(setValue(control, null)), - nshmpLibSha: state.form.value.overrideNshmpLib - ? enable - : control => disable(setValue(control, null)), - }), - })(state.form); - - return { - ...state, - form, - }; - } - default: - return { - ...state, - }; - } - }), - /** Handle import calculation configuration file action */ - on(actions.importCalcConfigFile, (state, {calcConfig}) => { - return { - ...state, - calcConfig: { - ...state.calcConfig, - ...calcConfig, - }, - }; - }), - /** Handle import configuration file action */ - on(actions.importConfigFile, (state, {config}) => { - const setAction = new SetValueAction(state.form.id, { - ...DEFAULT_FORM_VALUES, - ...config, - }); - let form = formGroupReducer(state.form, setAction); - - const overrideNshmpLib = - config?.nshmpConfig?.nshmpLibGitUrl || config?.nshmpConfig?.nshmpLibSha; - - form = updateGroup<RunNshmpHazForm>({ - nshmpConfig: updateGroup<NshmpConfig>({ - nshmpLibGitUrl: overrideNshmpLib - ? enable - : control => disable(setValue(control, null)), - nshmpLibSha: overrideNshmpLib - ? enable - : control => disable(setValue(control, null)), - }), - overrideNshmpLib: control => - overrideNshmpLib ? setValue(control, true) : setValue(control, false), - })(form); - - form = formGroupReducer(form, new MarkAsDirtyAction(state.form.id)); - form = formGroupReducer(form, new MarkAsTouchedAction(state.form.id)); - - return { - ...state, - calcConfig: { - ...state.calcConfig, - ...config.calcConfig, - }, - form, - }; - }), - /** Handle reset form aciton */ - on(actions.resetForm, state => { - const resetAction = new ResetAction(state.form.id); - const setAction = new SetValueAction(state.form.id, DEFAULT_FORM_VALUES); - let form = formGroupReducer(state.form, resetAction); - form = formGroupReducer(form, setAction); - - return { - ...state, - form, - }; - }), - /** Handle service response action */ - on(actions.serviceResponse, (state, {serviceResponse}) => { - return { - ...state, - serviceResponse, - }; - }) - ), -}); - -/** - * Application NGRX reducer with validators. - */ -submitHazJobsAppFeature.reducer = wrapReducerWithFormStateUpdate( - submitHazJobsAppFeature.reducer, - state => state.form, - validateForm -); diff --git a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.state.ts b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.state.ts index 0d9cd9b915ca75929bc9bfb80b655049f16a14ee..5180fccadfd6424c40a2488c264bce75693da758 100644 --- a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.state.ts +++ b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/state/app.state.ts @@ -1,41 +1,9 @@ -import {RunNshmpHazForm} from '@ghsc/nshmp-lib-ng/aws'; import { CalcConfig, - NshmpConfig, RunNshmpHazHttpPostConfig, RunNshmpHazResponseData, } from '@ghsc/nshmp-utils-ts/libs/aws/run-nshmp-haz'; import {Response} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws-utils'; -import { - createFormGroupState, - disable, - enable, - FormGroupState, - updateGroup, -} from 'ngrx-forms'; - -import {NshmpHazClass} from '../models/nshmp-haz-class.model'; -import {DEFAULT_FORM_VALUES} from '../utils/app.default-values'; - -/** Control form id for ngrx-forms */ -export const FORM_ID = '[ngrx-forms] AWS Submit Jobs Form'; - -const formState = createFormGroupState<RunNshmpHazForm>(FORM_ID, { - ...DEFAULT_FORM_VALUES, -}); - -/** Initial control form state */ -export const INITIAL_FORM_STATE = updateGroup<RunNshmpHazForm>({ - nshmpConfig: updateGroup<NshmpConfig>({ - nshmpLibGitUrl: formState.value.overrideNshmpLib ? enable : disable, - nshmpLibSha: formState.value.overrideNshmpLib ? enable : disable, - returnPeriod: - formState.value.nshmpConfig.className === - NshmpHazClass.DISAGG_CALC.toString() - ? enable - : disable, - }), -})(formState); /** * Application NGRX state. @@ -43,8 +11,6 @@ export const INITIAL_FORM_STATE = updateGroup<RunNshmpHazForm>({ export interface AppState { /** The calucation configuration */ calcConfig: CalcConfig; - /** Form field state */ - form: FormGroupState<RunNshmpHazForm>; /** Submit hazard job service response */ serviceResponse: Response<RunNshmpHazHttpPostConfig, RunNshmpHazResponseData>; } @@ -55,6 +21,5 @@ export interface AppState { export const INITIAL_STATE: AppState = { calcConfig: null, - form: INITIAL_FORM_STATE, serviceResponse: null, }; diff --git a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/utils/app-form.validators.ts b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/utils/app-form.validators.ts index 710a82cb56fb2573196c3be6456699f60486d67d..b81ba7d13b435196ecc40d33ce6ec52b2dd84800 100644 --- a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/utils/app-form.validators.ts +++ b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/utils/app-form.validators.ts @@ -1,11 +1,10 @@ -import {RunNshmpHazForm} from '@ghsc/nshmp-lib-ng/aws'; +import {FormGroup, Validators} from '@angular/forms'; import {NumberBounds} from '@ghsc/nshmp-lib-ng/nshmp'; -import { - CloudConfig, - NshmpConfig, -} from '@ghsc/nshmp-utils-ts/libs/aws/run-nshmp-haz'; -import {FormControlState, updateGroup, validate} from 'ngrx-forms'; -import {email, pattern, required} from 'ngrx-forms/validation'; +import {FormGroupControls} from '@ghsc/nshmp-lib-no-ngrx/nshmp'; +import {CloudConfig} from '@ghsc/nshmp-utils-ts/libs/aws/run-nshmp-haz'; + +import {RunNshmpHazFormGroup} from '../models/form-group.model'; +import {NshmpHazClass} from '../models/nshmp-haz-class.model'; /** * Form field bounds. @@ -18,54 +17,75 @@ export const formBounds: Record<string, NumberBounds> = { }, }; -/** - * ngrx-form validators - */ -export const validateForm = updateGroup<RunNshmpHazForm>({ - cloudConfig: updateGroup<CloudConfig>({ - instanceType: validate([required, pattern(/^\S+$/)]), - }), - nshmpConfig: (nested, form) => - updateGroup<NshmpConfig>(nested, { - className: validate([required, pattern(/^\S+$/)]), - email: validate([ - required, - email, - pattern(/@usgs.gov$/), - pattern(/^\S+$/g), - ]), - modelGitUrl: validate([required, pattern(/.git$/), pattern(/^\S+$/)]), - modelPath: validate([pattern(/^\S+$/g)]), - modelSha: validate([required, pattern(/^\S+$/)]), - nshmpLibGitUrl: control => - validateNshmpLibGitUrl(control, form.value.overrideNshmpLib), - nshmpLibSha: control => - form.value.overrideNshmpLib - ? validate(control, required, pattern(/^\S+$/)) - : control, - siteFileUrl: validate([required, pattern(/^\S+$/)]), - sourceCodeGitUrl: validate([ - required, - pattern(/^\S+$/), - pattern(/.git$/), - ]), - sourceCodeSha: validate([required, pattern(/^\S+$/)]), - }), -}); +export function addValidators( + formGroup: FormGroup<RunNshmpHazFormGroup> +): void { + addCloudValidators(formGroup.controls.cloudConfig); + addNshmpValidators(formGroup); +} -/** - * Validate nshmp-lib. - * - * @param control The form control - * @param overrideNshmpLib Whether to use custom nshmp-lib - */ -function validateNshmpLibGitUrl( - control: FormControlState<string>, - overrideNshmpLib: boolean -): FormControlState<string> { - if (overrideNshmpLib) { - return validate(control, [required, pattern(/.git$/), pattern(/^\S+$/)]); - } else { - return control; - } +function addCloudValidators(cloudConfig: FormGroupControls<CloudConfig>): void { + cloudConfig.controls.instanceType.addValidators(control => + Validators.required(control) + ); +} + +function addNshmpValidators(formGroup: FormGroup<RunNshmpHazFormGroup>): void { + const controls = formGroup.controls.nshmpConfig.controls; + + controls.className.addValidators(control => Validators.required(control)); + + controls.email.addValidators([ + control => Validators.required(control), + control => Validators.email(control), + Validators.pattern(/@usgs.gov$/), + ]); + + controls.modelGitUrl.addValidators([ + control => Validators.required(control), + Validators.pattern(/.git$/), + ]); + + controls.modelSha.addValidators(control => Validators.required(control)); + + controls.siteFileUrl.addValidators(control => Validators.required(control)); + + controls.sourceCodeGitUrl.addValidators([ + control => Validators.required(control), + Validators.pattern(/.git$/), + ]); + + controls.returnPeriod.addValidators([ + control => { + if ( + formGroup.getRawValue().nshmpConfig.className === + NshmpHazClass.DISAGG_CALC.toString() + ) { + return Validators.required(control); + } else { + return control; + } + }, + ]); + + controls.nshmpLibGitUrl.addValidators([ + control => { + if (formGroup.getRawValue().overrideNshmpLib) { + return Validators.required(control); + } else { + return control; + } + }, + Validators.pattern(/.git$/), + ]); + + controls.nshmpLibSha.addValidators([ + control => { + if (formGroup.getRawValue().overrideNshmpLib) { + return Validators.required(control); + } else { + return control; + } + }, + ]); } diff --git a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/utils/app.default-values.ts b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/utils/app.default-values.ts index a5a089780386c85e6157e7ad7b6e73f42c41439f..3268233538aaf5f4e846abfb7cca5844f53788b5 100644 --- a/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/utils/app.default-values.ts +++ b/projects/nshmp-apps/src/app/dev/aws/submit-haz-jobs/utils/app.default-values.ts @@ -1,4 +1,4 @@ -import {RunNshmpHazForm} from '@ghsc/nshmp-lib-ng/aws'; +import {RunNshmpHazForm} from '@ghsc/nshmp-lib-no-ngrx/aws'; import {NshmpHazClass} from '../models/nshmp-haz-class.model';