Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bases/behave_components/resources/public/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -1345,6 +1345,7 @@ p {
.input-number__error {
color: var(--error);
font-size: var(--font-size-10);
margin-top: 3px;
}

.input-number--disabled .input-number__input,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
;;==============================================================================

#_{:clj-kondo/ignore [:shadowed-var]}
(defn number-input [{:keys [label id name on-change on-blur disabled? error? error-msg min max value value-atom default-value step]}]
(defn number-input [{:keys [label id name on-change on-blur disabled? error? error-msg min max value value-atom default-value step placeholder]}]
[:div {:class ["input-number " (when error? "input-number--error")]}
[:label
{:class "input-number__label" :for id}
Expand All @@ -78,6 +78,7 @@
:min min
:max max}
step (assoc :step step)
placeholder (assoc :placeholder placeholder)
value (assoc :value value)
value-atom (assoc :value @value-atom)
default-value (assoc :default-value default-value))]
Expand Down
114 changes: 114 additions & 0 deletions development/migrations/2026_05_18_set_calculator_variable_min_max.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
(ns migrations.2026-05-18-set-calculator-variable-min-max
(:require [behave-cms.server :as cms]
[behave-cms.store :refer [default-conn]]
[datomic.api :as d]
[schema-migrate.interface :as sm]))

;; ===========================================================================================================
;; Overview
;; ===========================================================================================================
;; Sets :variable/minimum and :variable/maximum for calculator (tool) variables.
;;
;; All values are in native (English) units. The app handles unit conversion
;; for display when the user selects metric units.
;;
;; Probability of Ignition:
;; 1-h Fuel Moisture: 1 - 60
;; Air Temperature: -40 - 120 (F)
;; Fuel Shading from the Sun: 0 - 100
;;
;; Vapor Pressure Deficit:
;; Air Temperature: -40 - 120 (F)
;; Relative Humidity: 0 - 100
;;
;; Relative Humidity:
;; Dry Bulb Temperature: -40 - 120 (F)
;; Wet Bulb Temperature: -40 - 120 (F)
;; Site Elevation: 0 - 10,000
;;
;; SSD / SZS:
;; Vegetation Height: 0 - 300 (ft)

;; ===========================================================================================================
;; Initialize
;; ===========================================================================================================

(cms/init-db!)

#_{:clj-kondo/ignore [:missing-docstring]}
(def conn (default-conn))

;; ===========================================================================================================
;; Payload
;; ===========================================================================================================

#_{:clj-kondo/ignore [:missing-docstring]}
(def payload
[{:db/id (sm/name->eid conn :variable/name "1-h Fuel Moisture")
:variable/minimum 1.0
:variable/maximum 60.0}

{:db/id (sm/name->eid conn :variable/name "Air Temperature")
:variable/minimum -40.0
:variable/maximum 120.0}

{:db/id (sm/name->eid conn :variable/name "Fuel Shading from the Sun")
:variable/minimum 0.0
:variable/maximum 100.0}

{:db/id (sm/name->eid conn :variable/name "Relative Humidity")
:variable/minimum 0.0
:variable/maximum 100.0}

{:db/id (sm/name->eid conn :variable/name "Dry Bulb Temperature")
:variable/minimum -40.0
:variable/maximum 120.0}

{:db/id (sm/name->eid conn :variable/name "Wet Bulb Temperature")
:variable/minimum -40.0
:variable/maximum 120.0}

{:db/id (sm/name->eid conn :variable/name "Site Elevation")
:variable/minimum 0.0
:variable/maximum 10000.0}

{:db/id (sm/name->eid conn :variable/name "Vegetation Height")
:variable/minimum 0.0
:variable/maximum 300.0}])

;; ===========================================================================================================
;; Transact Payload
;; ===========================================================================================================

(comment
#_{:clj-kondo/ignore [:missing-docstring]}
(try (def tx-data @(d/transact conn payload))
(catch Exception e (str "caught exception: " (.getMessage e)))))

;; ===========================================================================================================
;; Verify
;; ===========================================================================================================

(comment
(let [variable-names ["1-h Fuel Moisture"
"Air Temperature"
"Fuel Shading from the Sun"
"Relative Humidity"
"Dry Bulb Temperature"
"Wet Bulb Temperature"
"Site Elevation"
"Vegetation Height"]]
(doseq [vname variable-names]
(let [eid (sm/name->eid conn :variable/name vname)
e (d/entity (d/db conn) eid)]
(println (format "%-30s min: %-8s max: %s"
vname
(:variable/minimum e)
(:variable/maximum e)))))))

;; ===========================================================================================================
;; In case we need to rollback.
;; ===========================================================================================================

(comment
(sm/rollback-tx! conn tx-data))
24 changes: 18 additions & 6 deletions projects/behave/resources/public/css/app-style.css
Original file line number Diff line number Diff line change
Expand Up @@ -1223,8 +1223,9 @@ body {

.tool-output,
.tool-input {
display: flex;
align-items: center;
display: grid;
grid-template-columns: auto 1fr;
align-items: start;
min-height: 40px;
padding-bottom: 5px;
}
Expand All @@ -1236,12 +1237,12 @@ body {
flex-direction: row;
}


.tool-output .input-text__label,
.tool-input .input-radio-group__label,
.tool-input__input > .input-dropdown > .input-dropdown__label,
.tool-input .input-number__label {
min-width: 250px;
padding: 0px;
}

.tool-input .input-dropdown__select-wrapper {
Expand All @@ -1250,12 +1251,18 @@ body {

.tool-input .input-number__label,
.tool-input .input-text__label,
.tool-input .input-dropdown__label,
.tool-input .input-dropdown__label {
padding: 7px 10px 0px 0px;
font-size: var(--font-size-15);
font-weight: 400;
color: var(--gray-5);
}

.tool-input .input-radio-group__label {
padding: 0px 10px 0px 0px;
font-size: var(--font-size-14);
font-size: var(--font-size-15);
font-weight: 400;
color: var(--gray-6);
color: var(--gray-5);
}

.tool-input + .tool-input:last-child {
Expand Down Expand Up @@ -1302,8 +1309,13 @@ body {
background-color: var(--white);
}

.tool-input .wizard-input__units {
padding-top: 12px;
}

.tool__units-system-selector {
padding-left: 5px;
margin-bottom: 15px;
}

.tool__units-system-selector .input-toggle__label {
Expand Down
112 changes: 104 additions & 8 deletions projects/behave/src/cljs/behave/tool/subs.cljs
Original file line number Diff line number Diff line change
@@ -1,9 +1,60 @@
(ns behave.tool.subs
(:require [behave.vms.store :as s]
[clojure.set :refer [rename-keys]]
(:require [behave.lib.units :refer [convert]]
[behave.translate :refer [<t]]
[behave.vms.store :as s]
[clojure.set :refer [rename-keys]]
[datascript.core :as d]
[re-frame.core :refer [reg-sub path] :as rf]))
[goog.string :as gstring]
[number-utils.interface :refer [parse-float]]
[re-frame.core :refer [reg-sub] :as rf]))

;;; Helpers

(defn- in-range?
"True when v falls within [v-min v-max]. Nil bounds are open."
[v-min v-max v]
(cond
(and (some? v-min) (some? v-max)) (<= v-min v v-max)
(some? v-min) (<= v-min v)
(some? v-max) (<= v v-max)
:else true))

(defn- converted-bounds
"Converts var-min/var-max from native to selected units (floored)."
[native-unit-uuid selected-unit-uuid var-min var-max]
(let [from-sc (when native-unit-uuid
(:unit/short-code (d/entity @@s/vms-conn [:bp/uuid native-unit-uuid])))
to-sc (when selected-unit-uuid
(:unit/short-code (d/entity @@s/vms-conn [:bp/uuid selected-unit-uuid])))]
(if (and from-sc to-sc (not= from-sc to-sc))
[(when var-min (convert var-min from-sc to-sc 0))
(when var-max (convert var-max from-sc to-sc 0))]
[var-min var-max])))

(defn- outside-range?
[native-unit-uuid selected-unit-uuid var-min var-max value]
(when (and (or var-min var-max) value (seq (str value)))
(when-let [v (parse-float (str value))]
(let [[adj-min adj-max] (converted-bounds native-unit-uuid selected-unit-uuid var-min var-max)]
(not (in-range? adj-min adj-max v))))))

(defn- range-placeholder
"Returns a range string like '1 - 60' with bounds converted to selected units."
[native-unit-uuid selected-unit-uuid var-min var-max]
(when (and var-min var-max)
(let [[adj-min adj-max] (converted-bounds native-unit-uuid selected-unit-uuid var-min var-max)]
(str (int adj-min) " - " (int adj-max)))))

(defn- outside-range-error-msg
"Returns an error message when value is outside the converted range."
[native-unit-uuid selected-unit-uuid var-min var-max value]
(when (and (or var-min var-max) value (seq (str value)))
(when-let [v (parse-float (str value))]
(let [[adj-min adj-max] (converted-bounds native-unit-uuid selected-unit-uuid var-min var-max)]
(when-not (in-range? adj-min adj-max v)
(gstring/format "Error: Not within range (min: %2f, max: %2f)" adj-min adj-max))))))

;;; Subscriptions

(reg-sub
:tool/show-tool-selector?
Expand Down Expand Up @@ -146,9 +197,54 @@
:subtool-variable/translation-key)]
@(<t translation-key))))

(comment
(rf/subscribe [:tool/all-inputs
"64e5023e-1b70-4b55-8312-6578fc9c64a9"
"64e5024c-1841-4fd6-ba62-e6f983608793"])
(reg-sub
:tool/input-range-placeholder
(fn [_ [_ native-unit-uuid var-min var-max effective-unit-uuid]]
(range-placeholder native-unit-uuid effective-unit-uuid var-min var-max)))

(reg-sub
:tool/input-error-msg
(fn [_ [_ _ _ _ native-unit-uuid var-min var-max effective-unit-uuid value]]
(outside-range-error-msg native-unit-uuid effective-unit-uuid var-min var-max value)))

(reg-sub
:tool/all-inputs-filled?
(fn [[_ tool-uuid subtool-uuid]]
[(rf/subscribe [:subtool/input-variables subtool-uuid])
(rf/subscribe [:tool/all-inputs tool-uuid subtool-uuid])])
(fn [[input-variables all-inputs] _]
(every? (fn [{sv-uuid :bp/uuid}]
(some? (:input/value (get all-inputs sv-uuid))))
input-variables)))

(rf/subscribe [:tool/all-output-uuids "64e5024c-1841-4fd6-ba62-e6f983608793"]))
(reg-sub
:tool/any-input-outside-range?
(fn [[_ tool-uuid subtool-uuid]]
[(rf/subscribe [:subtool/input-variables subtool-uuid])
(rf/subscribe [:tool/all-inputs tool-uuid subtool-uuid])
(rf/subscribe [:settings/tool-units-system])])
(fn [[input-variables all-inputs units-system] _]
(boolean
(some (fn [{var-min :variable/minimum
var-max :variable/maximum
sv-uuid :bp/uuid
kind :variable/kind
nat-uuid :variable/native-unit-uuid
eng-uuid :variable/english-unit-uuid
met-uuid :variable/metric-unit-uuid
domain-uuid :variable/domain-uuid}]
(when (= kind :continuous)
(let [domain (when domain-uuid (d/entity @@s/vms-conn [:bp/uuid domain-uuid]))
native-uuid (or (:domain/native-unit-uuid domain) nat-uuid)
english-uuid (or (:domain/english-unit-uuid domain) eng-uuid)
metric-uuid (or (:domain/metric-unit-uuid domain) met-uuid)
input (get all-inputs sv-uuid)
value (:input/value input)
per-input-uuid (:input/units-uuid input)
effective-uuid (or per-input-uuid
(case units-system
:english english-uuid
:metric metric-uuid
native-uuid))]
(outside-range? native-uuid effective-uuid var-min var-max value))))
input-variables))))
Loading
Loading