diff --git a/src/App.re b/src/App.re index 8b6ef967..95c76f31 100644 --- a/src/App.re +++ b/src/App.re @@ -1,11 +1,13 @@ type route = | Model(string) + | DistBuilder | Home | NotFound; let routeToPath = route => switch (route) { - | Model(i) => "/m/" ++ i + | Model(modelId) => "/m/" ++ modelId + | DistBuilder => "/dist-builder" | Home => "/" | _ => "/" }; @@ -66,11 +68,14 @@ module Menu = { {"Home" |> E.ste} {Models.all |> E.A.fmap((model: Prop.Model.t) => { - + {model.name |> E.ste} }) |> ReasonReact.array} + + {"Dist Builder" |> E.ste} + ; }; }; @@ -82,6 +87,7 @@ let make = () => { let routing = switch (url.path) { | ["m", modelId] => Model(modelId) + | ["dist-builder"] => DistBuilder | [] => Home | _ => NotFound }; @@ -89,13 +95,14 @@ let make = () => {
{switch (routing) { - | Model(n) => - switch (Models.getById(n)) { - | Some(model) => + | Model(id) => + switch (Models.getById(id)) { + | Some(model) => | None =>
{"Page is not found" |> E.ste}
} + | DistBuilder => | Home =>
{"Welcome" |> E.ste}
| _ =>
{"Page is not found" |> E.ste}
}}
; -}; \ No newline at end of file +}; diff --git a/src/components/DistBuilder.re b/src/components/DistBuilder.re new file mode 100644 index 00000000..fc5d891d --- /dev/null +++ b/src/components/DistBuilder.re @@ -0,0 +1,278 @@ +open BsReform; + +module FormConfig = [%lenses + type state = { + guesstimatorString: string, + // + domainType: string, // Complete, LeftLimited(...), RightLimited(...), LeftAndRightLimited(..., ...) + xPoint: string, + xPoint2: string, + excludingProbabilityMass: string, + excludingProbabilityMass2: string, + // + unitType: string, // UnspecifiedDistribution, TimeDistribution(zero, unit) + zero: MomentRe.Moment.t, + unit: string, + } +]; + +module Form = ReForm.Make(FormConfig); + +let schema = Form.Validation.Schema([||]); + +module FieldString = { + [@react.component] + let make = (~field, ~label) => { + + E.ste}> + validate()} + /> + + } + />; + }; +}; + +module Styles = { + open Css; + let row = + style([display(`flex), selector("div > div", [flex(`num(1.))])]); + let form = style([backgroundColor(hex("eee")), padding(em(1.))]); + let spacer = style([marginTop(em(3.))]); +}; + +module FieldFloat = { + [@react.component] + let make = (~field, ~label) => { + + E.ste}> + validate()} + /> + + } + />; + }; +}; + +[@react.component] +let make = () => { + let reform = + Form.use( + ~validationStrategy=OnDemand, + ~schema, + ~onSubmit=({state}) => {None}, + ~initialState={ + guesstimatorString: "mm(5 to 20, floor(normal(20,2)), [.5, .5])", + domainType: "Complete", + xPoint: "50.0", + xPoint2: "60.0", + excludingProbabilityMass2: "0.5", + excludingProbabilityMass: "0.3", + unitType: "UnspecifiedDistribution", + zero: MomentRe.momentNow(), + unit: "days", + }, + (), + ); + + let onSubmit = e => { + e->ReactEvent.Synthetic.preventDefault; + reform.submit(); + }; + + let domain = + switch (reform.state.values.domainType) { + | "Complete" => DistTypes.Complete + | "LeftLimited" => + LeftLimited({ + xPoint: reform.state.values.xPoint |> float_of_string, + excludingProbabilityMass: + reform.state.values.excludingProbabilityMass |> float_of_string, + }) + | "RightLimited" => + RightLimited({ + xPoint: reform.state.values.xPoint |> float_of_string, + excludingProbabilityMass: + reform.state.values.excludingProbabilityMass |> float_of_string, + }) + | "LeftAndRightLimited" => + LeftAndRightLimited( + { + xPoint: reform.state.values.xPoint |> float_of_string, + excludingProbabilityMass: + reform.state.values.excludingProbabilityMass |> float_of_string, + }, + { + xPoint: reform.state.values.xPoint2 |> float_of_string, + excludingProbabilityMass: + reform.state.values.excludingProbabilityMass2 |> float_of_string, + }, + ) + | _ => Js.Exn.raiseError("domain is unknown") + }; + + let unit = + switch (reform.state.values.unitType) { + | "UnspecifiedDistribution" => DistTypes.UnspecifiedDistribution + | "TimeDistribution" => + TimeDistribution({ + zero: reform.state.values.zero, + unit: reform.state.values.unit |> TimeTypes.TimeUnit.ofString, + }) + | _ => Js.Exn.raiseError("unit is unknown") + }; + + let guesstimatorString = reform.state.values.guesstimatorString; + +
+
+
+
+ {DistPlusIngredients.make(~guesstimatorString, ~domain, ~unit, ()) + |> DistPlusIngredients.toDistPlus( + ~sampleCount=10000, + ~outputXYPoints=2000, + ~truncateTo=Some(1000), + ) + |> E.O.React.fmapOrNull(distPlus => )} +
+
+
+
+ + + +
+
+ + E.ste}> + e |> handleChange}> + + {"Complete" |> E.ste} + + + {"Left Limited" |> E.ste} + + + {"Right Limited" |> E.ste} + + + {"Left And Right Limited" |> E.ste} + + + + } + /> +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ + E.ste}> + e |> handleChange}> + + {"Unspecified Distribution" |> E.ste} + + + {"Time Distribution" |> E.ste} + + + + } + /> +
+
+ + E.ste}> + { + e |> handleChange; + _ => (); + }} + /> + + } + /> +
+
+ + E.ste}> + e |> handleChange}> + + {"days" |> E.ste} + + + {"hours" |> E.ste} + + + {"milliseconds" |> E.ste} + + + {"minutes" |> E.ste} + + + {"months" |> E.ste} + + + {"quarters" |> E.ste} + + + {"seconds" |> E.ste} + + + {"weeks" |> E.ste} + + + {"years" |> E.ste} + + + + } + /> +
+
+
+
+
+
; +}; diff --git a/src/distributions/TimeTypes.re b/src/distributions/TimeTypes.re index 7a8368e0..3340ea32 100644 --- a/src/distributions/TimeTypes.re +++ b/src/distributions/TimeTypes.re @@ -33,6 +33,20 @@ module TimeUnit = { | `weeks => "weeks" | `years => "years" }; + + let ofString = (timeUnit: string) => + switch (timeUnit) { + | "days" => `days + | "hours" => `hours + | "milliseconds" => `milliseconds + | "minutes" => `minutes + | "months" => `months + | "quarters" => `quarters + | "seconds" => `seconds + | "weeks" => `weeks + | "years" => `years + | _ => Js.Exn.raiseError("TimeUnit is unknown") + }; }; module TimePoint = { @@ -72,4 +86,4 @@ module RelativeTimePoint = { | Time(r) => _timeToX(r, timeVector.zero, timeVector.unit) | XValue(r) => r }; -}; \ No newline at end of file +};