diff --git a/frontend/src/components/index.ts b/frontend/src/components/index.ts index f378e524d..659bee90a 100644 --- a/frontend/src/components/index.ts +++ b/frontend/src/components/index.ts @@ -12,7 +12,14 @@ export { default as AppTabs } from './core/AppTabs.vue' export { default as ReportConfiguration } from './input/ReportConfiguration.vue' export { default as SpeciesListInput } from './input/species-info/SpeciesListInput.vue' +export { default as SpeciesGroupsDisplay } from './input/species-info/SpeciesGroupsDisplay.vue' +export { default as SpeciesInfoPanel } from './input/species-info/SpeciesInfoPanel.vue' +export { default as SiteInfoPanel } from './input/site-info/SiteInfoPanel.vue' +export { default as StandDensityPanel } from './input/stand-density/StandDensityPanel.vue' +export { default as ReportInfoPanel } from './input/report-info/ReportInfoPanel.vue' + +export { default as FileUpload } from './input/file-upload/FileUpload.vue' export { default as BCLogo } from './layout/BCLogo.vue' export { default as HeaderTitle } from './layout/HeaderTitle.vue' export { default as TheHeader } from './layout/TheHeader.vue' diff --git a/frontend/src/views/FileUpload.vue b/frontend/src/components/input/file-upload/FileUpload.vue similarity index 64% rename from frontend/src/views/FileUpload.vue rename to frontend/src/components/input/file-upload/FileUpload.vue index 9a4b5be64..8202f53de 100644 --- a/frontend/src/views/FileUpload.vue +++ b/frontend/src/components/input/file-upload/FileUpload.vue @@ -93,7 +93,7 @@ import { } from '@/components' import type { MessageDialog } from '@/interfaces/interfaces' import { CONSTANTS, MESSAGE, DEFAULTS } from '@/constants' -import { FileUploadValidator } from '@/validation/fileUploadValidator' +import { fileUploadValidation } from '@/validation' import { Util } from '@/utils/util' import { logSuccessMessage } from '@/utils/messageHandler' @@ -102,8 +102,6 @@ const form = ref() const isProgressVisible = ref(false) const progressMessage = ref('') -const fileUploadValidator = new FileUploadValidator() - const startingAge = ref(DEFAULTS.DEFAULT_VALUES.STARTING_AGE) const finishingAge = ref(DEFAULTS.DEFAULT_VALUES.FINISHING_AGE) const ageIncrement = ref(DEFAULTS.DEFAULT_VALUES.AGE_INCREMENT) @@ -151,140 +149,105 @@ const handleReportTitleUpdate = (value: string | null) => { reportTitle.value = value } -const validateComparison = (): boolean => { - if ( - !fileUploadValidator.validateAgeComparison( - finishingAge.value, +const runModelHandler = async () => { + try { + // validation - comparison + const comparisonResult = fileUploadValidation.validateComparison( startingAge.value, + finishingAge.value, ) - ) { - messageDialog.value = { - dialog: true, - title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, - message: MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_COMP_FNSH_AGE, - btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, - } - return false - } - - return true -} - -const validateRange = (): boolean => { - if (!fileUploadValidator.validateStartingAgeRange(startingAge.value)) { - messageDialog.value = { - dialog: true, - title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, - message: MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_START_AGE_RNG( - CONSTANTS.NUM_INPUT_LIMITS.STARTING_AGE_MIN, - CONSTANTS.NUM_INPUT_LIMITS.STARTING_AGE_MAX, - ), - btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, - } - return false - } - - if (!fileUploadValidator.validateFinishingAgeRange(finishingAge.value)) { - messageDialog.value = { - dialog: true, - title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, - message: MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_START_FNSH_RNG( - CONSTANTS.NUM_INPUT_LIMITS.FINISHING_AGE_MIN, - CONSTANTS.NUM_INPUT_LIMITS.FINISHING_AGE_MAX, - ), - btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, - } - return false - } - - if (!fileUploadValidator.validateAgeIncrementRange(ageIncrement.value)) { - messageDialog.value = { - dialog: true, - title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, - message: MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_AGE_INC_RNG( - CONSTANTS.NUM_INPUT_LIMITS.AGE_INC_MIN, - CONSTANTS.NUM_INPUT_LIMITS.AGE_INC_MAX, - ), - btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, - } - return false - } - - return true -} - -const validateFiles = async () => { - if (!layerFile.value) { - messageDialog.value = { - dialog: true, - title: MESSAGE.MSG_DIALOG_TITLE.MISSING_FILE, - message: MESSAGE.FILE_UPLOAD_ERR.LAYER_FILE_MISSING, - btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, - } - return false - } - - if (!polygonFile.value) { - messageDialog.value = { - dialog: true, - title: MESSAGE.MSG_DIALOG_TITLE.MISSING_FILE, - message: MESSAGE.FILE_UPLOAD_ERR.POLYGON_FILE_MISSING, - btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, + if (!comparisonResult.isValid) { + messageDialog.value = { + dialog: true, + title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, + message: MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_COMP_FNSH_AGE, + btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, + } + return } - return false - } - if (!(await fileUploadValidator.isCSVFile(layerFile.value))) { - messageDialog.value = { - dialog: true, - title: MESSAGE.MSG_DIALOG_TITLE.INVALID_FILE, - message: MESSAGE.FILE_UPLOAD_ERR.LAYER_FILE_NOT_CSV_FORMAT, - btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, - } - return false - } - - if (!(await fileUploadValidator.isCSVFile(polygonFile.value))) { - messageDialog.value = { - dialog: true, - title: MESSAGE.MSG_DIALOG_TITLE.INVALID_FILE, - message: MESSAGE.FILE_UPLOAD_ERR.POLYGON_FILE_NOT_CSV_FORMAT, - btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, + // validation - required fields + const requiredFieldsResult = fileUploadValidation.validateRequiredFields( + startingAge.value, + finishingAge.value, + ageIncrement.value, + ) + if (!requiredFieldsResult.isValid) { + messageDialog.value = { + dialog: true, + title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, + message: MESSAGE.FILE_UPLOAD_ERR.RPT_VLD_REQUIRED_FIELDS, + btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, + } + return } - return false - } - - return true -} -const validateRequiredFields = (): boolean => { - if ( - !fileUploadValidator.validateRequiredFields( + // validation - range + const rangeResult = fileUploadValidation.validateRange( startingAge.value, finishingAge.value, ageIncrement.value, ) - ) { - messageDialog.value = { - dialog: true, - title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, - message: MESSAGE.FILE_UPLOAD_ERR.RPT_VLD_REQUIRED_FIELDS, - btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, + if (!rangeResult.isValid) { + let message = '' + switch (rangeResult.errorType) { + case 'startingAge': + message = MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_START_AGE_RNG( + CONSTANTS.NUM_INPUT_LIMITS.STARTING_AGE_MIN, + CONSTANTS.NUM_INPUT_LIMITS.STARTING_AGE_MAX, + ) + break + case 'finishingAge': + message = MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_START_FNSH_RNG( + CONSTANTS.NUM_INPUT_LIMITS.FINISHING_AGE_MIN, + CONSTANTS.NUM_INPUT_LIMITS.FINISHING_AGE_MAX, + ) + break + case 'ageIncrement': + message = MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_AGE_INC_RNG( + CONSTANTS.NUM_INPUT_LIMITS.AGE_INC_MIN, + CONSTANTS.NUM_INPUT_LIMITS.AGE_INC_MAX, + ) + break + } + + messageDialog.value = { + dialog: true, + title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, + message: message, + btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, + } + return } - return false - } - return true -} -const runModelHandler = async () => { - try { - const isValidationSuccessful = - validateRequiredFields() && - validateComparison() && - validateRange() && - (await validateFiles()) - - if (!isValidationSuccessful) { + // validation - files + const filesResult = await fileUploadValidation.validateFiles( + layerFile.value, + polygonFile.value, + ) + if (!filesResult.isValid) { + let message = '' + switch (filesResult.errorType) { + case 'layerFileMissing': + message = MESSAGE.FILE_UPLOAD_ERR.LAYER_FILE_MISSING + break + case 'polygonFileMissing': + message = MESSAGE.FILE_UPLOAD_ERR.POLYGON_FILE_MISSING + break + case 'layerFileNotCSVFormat': + message = MESSAGE.FILE_UPLOAD_ERR.LAYER_FILE_NOT_CSV_FORMAT + break + case 'polygonFileNotCSVFormat': + message = MESSAGE.FILE_UPLOAD_ERR.POLYGON_FILE_NOT_CSV_FORMAT + break + } + + messageDialog.value = { + dialog: true, + title: MESSAGE.MSG_DIALOG_TITLE.INVALID_FILE, + message: message, + btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, + } return } diff --git a/frontend/src/components/model-param-selection-panes/ReportInfo.vue b/frontend/src/components/input/report-info/ReportInfoPanel.vue similarity index 73% rename from frontend/src/components/model-param-selection-panes/ReportInfo.vue rename to frontend/src/components/input/report-info/ReportInfoPanel.vue index b1124a862..326998f64 100644 --- a/frontend/src/components/model-param-selection-panes/ReportInfo.vue +++ b/frontend/src/components/input/report-info/ReportInfoPanel.vue @@ -68,12 +68,10 @@ import { } from '@/components' import { CONSTANTS, DEFAULTS, MESSAGE } from '@/constants' import type { MessageDialog } from '@/interfaces/interfaces' -import { ReportInfoValidator } from '@/validation/reportInfoValidator' +import { reportInfoValidation } from '@/validation' const form = ref() -const reportInfoValidator = new ReportInfoValidator() - const modelParameterStore = useModelParameterStore() const messageDialog = ref({ @@ -129,81 +127,70 @@ const handleReportTitleUpdate = (value: string | null) => { reportTitle.value = value } -const validateComparison = (): boolean => { - if ( - !reportInfoValidator.validateAgeComparison( - finishingAge.value, - startingAge.value, - ) - ) { +const onConfirm = () => { + // validation - comparison + const comparisonResult = reportInfoValidation.validateComparison( + startingAge.value, + finishingAge.value, + ) + if (!comparisonResult.isValid) { messageDialog.value = { dialog: true, title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, message: MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_COMP_FNSH_AGE, btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, } - - return false + return } - return true -} - -const validateRange = (): boolean => { - if (!reportInfoValidator.validateStartingAgeRange(startingAge.value)) { - messageDialog.value = { - dialog: true, - title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, - message: MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_START_AGE_RNG( - CONSTANTS.NUM_INPUT_LIMITS.STARTING_AGE_MIN, - CONSTANTS.NUM_INPUT_LIMITS.STARTING_AGE_MAX, - ), - btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, + // validation - range + const rangeResult = reportInfoValidation.validateRange( + startingAge.value, + finishingAge.value, + ageIncrement.value, + ) + + if (!rangeResult.isValid) { + let message = '' + switch (rangeResult.errorType) { + case 'startingAge': + message = MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_START_AGE_RNG( + CONSTANTS.NUM_INPUT_LIMITS.STARTING_AGE_MIN, + CONSTANTS.NUM_INPUT_LIMITS.STARTING_AGE_MAX, + ) + break + case 'finishingAge': + message = MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_START_FNSH_RNG( + CONSTANTS.NUM_INPUT_LIMITS.FINISHING_AGE_MIN, + CONSTANTS.NUM_INPUT_LIMITS.FINISHING_AGE_MAX, + ) + break + case 'ageIncrement': + message = MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_AGE_INC_RNG( + CONSTANTS.NUM_INPUT_LIMITS.AGE_INC_MIN, + CONSTANTS.NUM_INPUT_LIMITS.AGE_INC_MAX, + ) + break } - return false - } - if (!reportInfoValidator.validateFinishingAgeRange(finishingAge.value)) { messageDialog.value = { dialog: true, title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, - message: MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_START_FNSH_RNG( - CONSTANTS.NUM_INPUT_LIMITS.FINISHING_AGE_MIN, - CONSTANTS.NUM_INPUT_LIMITS.FINISHING_AGE_MAX, - ), + message: message, btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, } - return false + return } - if (!reportInfoValidator.validateAgeIncrementRange(ageIncrement.value)) { - messageDialog.value = { - dialog: true, - title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, - message: MESSAGE.MDL_PRM_INPUT_ERR.RPT_VLD_AGE_INC_RNG( - CONSTANTS.NUM_INPUT_LIMITS.AGE_INC_MIN, - CONSTANTS.NUM_INPUT_LIMITS.AGE_INC_MAX, - ), - btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, - } - return false + if (form.value) { + form.value.validate() + } else { + console.warn('Form reference is null. Validation skipped.') } - return true -} - -const onConfirm = () => { - if (validateComparison() && validateRange()) { - if (form.value) { - form.value.validate() - } else { - console.warn('Form reference is null. Validation skipped.') - } - - // this panel is not in a confirmed state - if (!isConfirmed.value) { - modelParameterStore.confirmPanel(panelName) - } + // this panel is not in a confirmed state + if (!isConfirmed.value) { + modelParameterStore.confirmPanel(panelName) } } diff --git a/frontend/src/components/model-param-selection-panes/SiteInfo.vue b/frontend/src/components/input/site-info/SiteInfoPanel.vue similarity index 93% rename from frontend/src/components/model-param-selection-panes/SiteInfo.vue rename to frontend/src/components/input/site-info/SiteInfoPanel.vue index 964cc111d..94e5eba21 100644 --- a/frontend/src/components/model-param-selection-panes/SiteInfo.vue +++ b/frontend/src/components/input/site-info/SiteInfoPanel.vue @@ -188,13 +188,11 @@ import { useModelParameterStore } from '@/stores/modelParameterStore' import { AppMessageDialog, AppPanelActions, AppSpinField } from '@/components' import type { SpeciesGroup, MessageDialog } from '@/interfaces/interfaces' import { CONSTANTS, OPTIONS, DEFAULTS, MESSAGE } from '@/constants' -import { SiteInfoValidator } from '@/validation/siteInfoValidator' +import { siteInfoValidation } from '@/validation' import { Util } from '@/utils/util' const form = ref() -const siteInfoValidator = new SiteInfoValidator() - const modelParameterStore = useModelParameterStore() const messageDialog = ref({ @@ -264,23 +262,20 @@ const handleBha50SiteIndexUpdate = (value: string | null) => { bha50SiteIndex.value = value } -const validateRange = (): boolean => { - if (!siteInfoValidator.validateBha50SiteIndexRange(bha50SiteIndex.value)) { - messageDialog.value = { - dialog: true, - title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, - message: MESSAGE.MDL_PRM_INPUT_ERR.SITE_VLD_SI_RNG, - btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, - } - - return false +const formattingValues = (): void => { + if (bha50SiteIndex.value) { + bha50SiteIndex.value = parseFloat(bha50SiteIndex.value).toFixed( + CONSTANTS.NUM_INPUT_LIMITS.BHA50_SITE_INDEX_DECIMAL_NUM, + ) } - - return true } -const validateRequiredFields = (): boolean => { - if (!siteInfoValidator.validateRequiredFields(bha50SiteIndex.value)) { +const onConfirm = () => { + // validation - required fields + const requiredResult = siteInfoValidation.validateRequiredFields( + bha50SiteIndex.value, + ) + if (!requiredResult.isValid) { messageDialog.value = { dialog: true, title: MESSAGE.MSG_DIALOG_TITLE.MISSING_INFO, @@ -289,35 +284,32 @@ const validateRequiredFields = (): boolean => { ), btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, } - - return false + return } - return true -} - -const formattingValues = (): void => { - if (bha50SiteIndex.value) { - bha50SiteIndex.value = parseFloat(bha50SiteIndex.value).toFixed( - CONSTANTS.NUM_INPUT_LIMITS.BHA50_SITE_INDEX_DECIMAL_NUM, - ) + // validation - range + const rangeResult = siteInfoValidation.validateRange(bha50SiteIndex.value) + if (!rangeResult.isValid) { + messageDialog.value = { + dialog: true, + title: MESSAGE.MSG_DIALOG_TITLE.INVALID_INPUT, + message: MESSAGE.MDL_PRM_INPUT_ERR.SITE_VLD_SI_RNG, + btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, + } + return } -} -const onConfirm = () => { - if (validateRequiredFields() && validateRange()) { - if (form.value) { - form.value.validate() - } else { - console.warn('Form reference is null. Validation skipped.') - } + if (form.value) { + form.value.validate() + } else { + console.warn('Form reference is null. Validation skipped.') + } - formattingValues() + formattingValues() - // this panel is not in a confirmed state - if (!isConfirmed.value) { - modelParameterStore.confirmPanel(panelName) - } + // this panel is not in a confirmed state + if (!isConfirmed.value) { + modelParameterStore.confirmPanel(panelName) } } diff --git a/frontend/src/components/input/species-info/SpeciesGroupsDisplay.vue b/frontend/src/components/input/species-info/SpeciesGroupsDisplay.vue new file mode 100644 index 000000000..70a478ad4 --- /dev/null +++ b/frontend/src/components/input/species-info/SpeciesGroupsDisplay.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/frontend/src/components/model-param-selection-panes/SpeciesInfo.vue b/frontend/src/components/input/species-info/SpeciesInfoPanel.vue similarity index 63% rename from frontend/src/components/model-param-selection-panes/SpeciesInfo.vue rename to frontend/src/components/input/species-info/SpeciesInfoPanel.vue index 4e35ed8cc..9e53f199e 100644 --- a/frontend/src/components/model-param-selection-panes/SpeciesInfo.vue +++ b/frontend/src/components/input/species-info/SpeciesInfoPanel.vue @@ -69,85 +69,7 @@ /> - - -
- - - - - - - - - - - -
-
-
- -
- - - - - -
-
+
@@ -194,16 +116,15 @@ import { AppMessageDialog, AppPanelActions, SpeciesListInput, + SpeciesGroupsDisplay, } from '@/components' import { CONSTANTS, DEFAULTS, MAPPINGS, MESSAGE, OPTIONS } from '@/constants' import type { SpeciesList, MessageDialog } from '@/interfaces/interfaces' -import { SpeciesInfoValidator } from '@/validation/speciesInfoValidator' +import { speciesInfoValidation } from '@/validation' import { cloneDeep } from 'lodash' const form = ref() -const speciesInfoValidator = new SpeciesInfoValidator() - const modelParameterStore = useModelParameterStore() const messageDialog = ref({ @@ -264,19 +185,20 @@ const handleSpeciesListUpdate = (updatedList: SpeciesList[]) => { } } -const validateDuplicateSpecies = () => { - const duplicateSpecies = speciesInfoValidator.validateDuplicateSpecies( +const onConfirm = () => { + // validation - duplicate + const duplicateSpeciesResult = speciesInfoValidation.validateDuplicateSpecies( speciesList.value, ) - if (duplicateSpecies) { + if (!duplicateSpeciesResult.isValid) { + const duplicateSpecies = + duplicateSpeciesResult.duplicateSpecies as keyof typeof MAPPINGS.SPECIES_MAP const speciesLabel = ( Object.keys(MAPPINGS.SPECIES_MAP) as Array< keyof typeof MAPPINGS.SPECIES_MAP > - ).find((key) => key === duplicateSpecies) - ? MAPPINGS.SPECIES_MAP[ - duplicateSpecies as keyof typeof MAPPINGS.SPECIES_MAP - ] + ).find((key) => key === duplicateSpeciesResult.duplicateSpecies) + ? MAPPINGS.SPECIES_MAP[duplicateSpecies] : '' const message = speciesLabel @@ -292,62 +214,45 @@ const validateDuplicateSpecies = () => { message: message, btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, } - - return false + return } - return true -} - -const validateTotalSpeciesPercent = () => { - if ( - !speciesInfoValidator.validateTotalSpeciesPercent( - totalSpeciesPercent.value, - totalSpeciesGroupPercent.value, - ) - ) { + // validation - total percent + const totalPercentResult = speciesInfoValidation.validateTotalSpeciesPercent( + totalSpeciesPercent.value, + totalSpeciesGroupPercent.value, + ) + if (!totalPercentResult.isValid) { messageDialog.value = { dialog: true, title: MESSAGE.MSG_DIALOG_TITLE.DATA_INCOMPLETE, message: MESSAGE.MDL_PRM_INPUT_ERR.SPCZ_VLD_TOTAL_PCT, btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, } - - return false + return } - return true -} -const validateRequired = () => { - if (!speciesInfoValidator.validateRequired(derivedBy.value)) { + // validation - required fields + const requiredResult = speciesInfoValidation.validateRequired(derivedBy.value) + if (!requiredResult.isValid) { messageDialog.value = { dialog: true, title: MESSAGE.MSG_DIALOG_TITLE.MISSING_INFO, message: MESSAGE.MDL_PRM_INPUT_ERR.SPCZ_VLD_MISSING_DERIVED_BY, btnLabel: CONSTANTS.BUTTON_LABEL.CONT_EDIT, } - - return false + return } - return true -} -const onConfirm = () => { - if ( - validateDuplicateSpecies() && - validateTotalSpeciesPercent() && - validateRequired() - ) { - if (form.value) { - form.value.validate() - } else { - console.warn('Form reference is null. Validation skipped.') - } + if (form.value) { + form.value.validate() + } else { + console.warn('Form reference is null. Validation skipped.') + } - // this panel is not in a confirmed state - if (!isConfirmed.value) { - modelParameterStore.confirmPanel(panelName) - } + // this panel is not in a confirmed state + if (!isConfirmed.value) { + modelParameterStore.confirmPanel(panelName) } } diff --git a/frontend/src/components/input/species-info/SpeciesListInput.vue b/frontend/src/components/input/species-info/SpeciesListInput.vue index 0c5aed626..7b0ca0b51 100644 --- a/frontend/src/components/input/species-info/SpeciesListInput.vue +++ b/frontend/src/components/input/species-info/SpeciesListInput.vue @@ -71,7 +71,7 @@ import { ref, onBeforeUnmount, watch, type PropType } from 'vue' import { CONSTANTS, MESSAGE } from '@/constants' import type { SpeciesList } from '@/interfaces/interfaces' -import { SpeciesInfoValidator } from '@/validation/speciesInfoValidator' +import { speciesInfoValidation } from '@/validation' import { Util } from '@/utils/util' import { cloneDeep } from 'lodash' @@ -106,8 +106,6 @@ const emit = defineEmits(['update:speciesList']) const localSpeciesList = ref(cloneDeep(props.speciesList)) -const speciesInfoValidator = new SpeciesInfoValidator() - // Watch for external speciesList changes watch( () => props.speciesList, @@ -219,9 +217,9 @@ const triggerSpeciesSortByPercent = () => { }) } -const validatePercent = (percent: any): boolean | string => { - const isValid = speciesInfoValidator.validatePercent(percent) - if (!isValid) { +const validatePercent = (percent: string | null): boolean | string => { + const validationResult = speciesInfoValidation.validatePercent(percent) + if (!validationResult.isValid) { return MESSAGE.MDL_PRM_INPUT_ERR.SPCZ_VLD_INPUT_RANGE( CONSTANTS.NUM_INPUT_LIMITS.SPECIES_PERCENT_MIN, CONSTANTS.NUM_INPUT_LIMITS.SPECIES_PERCENT_MAX, diff --git a/frontend/src/components/model-param-selection-panes/StandDensity.vue b/frontend/src/components/input/stand-density/StandDensityPanel.vue similarity index 73% rename from frontend/src/components/model-param-selection-panes/StandDensity.vue rename to frontend/src/components/input/stand-density/StandDensityPanel.vue index 439630e46..73c3def8a 100644 --- a/frontend/src/components/model-param-selection-panes/StandDensity.vue +++ b/frontend/src/components/input/stand-density/StandDensityPanel.vue @@ -16,7 +16,7 @@ {{ - panelOpenStates.standDensity === PANEL.OPEN + panelOpenStates.standDensity === CONSTANTS.PANEL.OPEN ? 'mdi-chevron-up' : 'mdi-chevron-down' }} @@ -34,9 +34,9 @@ label="% Stockable Area" type="number" v-model.number="percentStockableArea" - :max="NUM_INPUT_LIMITS.PERCENT_STOCKABLE_AREA_MAX" - :min="NUM_INPUT_LIMITS.PERCENT_STOCKABLE_AREA_MIN" - :step="NUM_INPUT_LIMITS.PERCENT_STOCKABLE_AREA_STEP" + :max="CONSTANTS.NUM_INPUT_LIMITS.PERCENT_STOCKABLE_AREA_MAX" + :min="CONSTANTS.NUM_INPUT_LIMITS.PERCENT_STOCKABLE_AREA_MIN" + :step="CONSTANTS.NUM_INPUT_LIMITS.PERCENT_STOCKABLE_AREA_STEP" placeholder="" persistent-placeholder hide-details @@ -47,7 +47,7 @@ {{ MDL_PRM_INPUT_HINT.SITE_DFT_COMPUTED }}{{ MESSAGE.MDL_PRM_INPUT_HINT.SITE_DFT_COMPUTED }} @@ -67,28 +67,16 @@ - -