diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/EditorTechnique.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/EditorTechnique.scala index 842cc828f96..8f7b484c1d8 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/EditorTechnique.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/EditorTechnique.scala @@ -51,8 +51,10 @@ import com.normation.rudder.ncf.Constraint.CheckResult import com.normation.rudder.ncf.Constraint.Constraint import java.util.regex.Pattern import zio.ZIO +import zio.json.SnakeCase import zio.json.jsonDiscriminator import zio.json.jsonHint +import zio.json.jsonMemberNames sealed trait NcfId { def value: String @@ -196,7 +198,8 @@ final case class TechniqueParameter( name: String, description: String, documentation: Option[String], - mayBeEmpty: Boolean + mayBeEmpty: Boolean, + constraints: Option[Constraints] ) object ParameterType { @@ -276,6 +279,17 @@ object ParameterType { } } +@jsonMemberNames(SnakeCase) +case class Constraints( + allowEmptyString: Option[Boolean], + allowWhiteSpaceString: Option[Boolean], + minLength: Option[Int], + maxLength: Option[Int], + regex: Option[String], + notRegex: Option[String], + select: Option[List[String]] +) + object Constraint { sealed trait Constraint { def check(value: String): CheckResult diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/TechniqueSerializer.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/TechniqueSerializer.scala index b7f62fbd0c4..2192480013c 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/TechniqueSerializer.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/TechniqueSerializer.scala @@ -66,6 +66,7 @@ class TechniqueSerializer(parameterTypeService: ParameterTypeService) { implicit val encoderMethodElem: JsonEncoder[MethodElem] = DeriveJsonEncoder.gen implicit val encoderTechniqueParameterType: JsonEncoder[ParameterType.ParameterType] = JsonEncoder[String].contramap(s => parameterTypeService.value(s).getOrElse(s.toString)) + implicit val encoderConstraints: JsonEncoder[Constraints] = DeriveJsonEncoder.gen implicit val encoderTechniqueParameter: JsonEncoder[TechniqueParameter] = DeriveJsonEncoder.gen implicit val encoderResourceFileState: JsonEncoder[ResourceFileState] = JsonEncoder[String].contramap(_.value) implicit val encoderResourceFile: JsonEncoder[ResourceFile] = DeriveJsonEncoder.gen @@ -83,6 +84,7 @@ class TechniqueSerializer(parameterTypeService: ParameterTypeService) { case Left(err) => Left(err.fullMsg) case Right(r) => Right(r) }) + implicit val decoderConstraints: JsonDecoder[Constraints] = DeriveJsonDecoder.gen implicit val decoderTechniqueParameter: JsonDecoder[TechniqueParameter] = DeriveJsonDecoder.gen implicit val decoderMethodElem: JsonDecoder[MethodElem] = DeriveJsonDecoder.gen implicit val decoderResourceFileState: JsonDecoder[ResourceFileState] = diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/migration/MigrateJsonTechniquesService.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/migration/MigrateJsonTechniquesService.scala index 4b1029961f3..085f04cb821 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/migration/MigrateJsonTechniquesService.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/migration/MigrateJsonTechniquesService.scala @@ -151,7 +151,7 @@ object MigrateJsonTechniquesService { desc, doc, oldTechnique.parameter.map(p => - TechniqueParameter(ParameterId(p.id), canonify(p.name), p.name, Some(p.description), p.mayBeEmpty) + TechniqueParameter(ParameterId(p.id), canonify(p.name), p.name, Some(p.description), p.mayBeEmpty, None) ), oldTechnique.resources.flatMap(s => ResourceFileState.parse(s.state).map(ResourceFile(s.name, _)).toSeq), Map(), diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/yaml/YamlTechnique.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/yaml/YamlTechnique.scala index 1ea53d5e700..c9c1d4f7fe7 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/yaml/YamlTechnique.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/ncf/yaml/YamlTechnique.scala @@ -97,10 +97,6 @@ case class TechniqueParameter( constraints: Constraints ) -case class Constraints( - allow_empty: Option[Boolean] -) - object YamlTechniqueSerializer { implicit val encoderParameterId: JsonEncoder[ParameterId] = JsonEncoder[String].contramap(_.value) implicit val encoderFieldParameterId: JsonFieldEncoder[ParameterId] = JsonFieldEncoder[String].contramap(_.value) @@ -223,7 +219,9 @@ object YamlTechniqueSerializer { techniqueParameter.name, techniqueParameter.description, techniqueParameter.documentation, - Constraints(allow_empty = Some(techniqueParameter.mayBeEmpty)) + techniqueParameter.constraints + .getOrElse(Constraints(None, None, None, None, None, None, None)) + .copy(allowEmptyString = Some(techniqueParameter.mayBeEmpty)) ) } @@ -233,7 +231,8 @@ object YamlTechniqueSerializer { techniqueParameter.name, techniqueParameter.description, techniqueParameter.documentation, - techniqueParameter.constraints.allow_empty.getOrElse(false) + techniqueParameter.constraints.allowEmptyString.getOrElse(false), + Some(techniqueParameter.constraints) ) } diff --git a/webapp/sources/rudder/rudder-core/src/test/scala/com/normation/rudder/ncf/TestEditorTechniqueWriter.scala b/webapp/sources/rudder/rudder-core/src/test/scala/com/normation/rudder/ncf/TestEditorTechniqueWriter.scala index f7d43eb75fb..4af08e117fc 100644 --- a/webapp/sources/rudder/rudder-core/src/test/scala/com/normation/rudder/ncf/TestEditorTechniqueWriter.scala +++ b/webapp/sources/rudder/rudder-core/src/test/scala/com/normation/rudder/ncf/TestEditorTechniqueWriter.scala @@ -513,7 +513,8 @@ class TestEditorTechniqueWriter extends Specification with ContentMatchers with "technique parameter", Some(" a long description, with line \n break within"), // we must ensure that it will lead to: [parameter(Mandatory=$false)] - true + true, + None ) :: Nil, Nil, Map(), @@ -661,7 +662,8 @@ class TestEditorTechniqueWriter extends Specification with ContentMatchers with "version", "package version", Some("Package version to install"), - false + false, + None ) :: Nil, Nil, Map(), @@ -752,7 +754,8 @@ class TestEditorTechniqueWriter extends Specification with ContentMatchers with "my_custom_condition", "my custom condition", None, - false + false, + None ) :: Nil, Nil, Map(), diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor.elm b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor.elm index 21cc92f0b18..5e7951b6345 100755 --- a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor.elm @@ -427,7 +427,7 @@ update msg model = newValidation = List.foldl ( \param val -> - accumulateErrorConstraint param (Maybe.withDefault [] (Dict.get param.id.value constraints)) val + accumulateErrorConstraint param (Maybe.withDefault defaultConstraint (Dict.get param.id.value constraints)) val ) b.validation realCall.parameters in @@ -497,7 +497,7 @@ update msg model = case model.mode of TechniqueDetails t o ui editInfo-> let - parameters = List.append t.parameters [ TechniqueParameter paramId "" "" Nothing False ] + parameters = List.append t.parameters [ TechniqueParameter paramId "" "" Nothing False defaultConstraint] in TechniqueDetails { t | parameters = parameters } o ui editInfo _ -> model.mode @@ -771,8 +771,8 @@ update msg model = calls = updateElemIf (getId >> (==) call.id ) (updateParameter paramId newValue) t.elems constraints = case Dict.get call.methodName.value model.methods of - Just m -> Maybe.withDefault [] (Maybe.map (.constraints) (List.Extra.find (.name >> (==) paramId) m.parameters)) - Nothing -> [] + Just m -> Maybe.withDefault defaultConstraint (Maybe.map (.constraints) (List.Extra.find (.name >> (==) paramId) m.parameters)) + Nothing -> defaultConstraint updateCallUi = \optCui -> let diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/DataTypes.elm b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/DataTypes.elm index fed01325e1e..043d8647fda 100755 --- a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/DataTypes.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/DataTypes.elm @@ -25,20 +25,23 @@ type alias Draft = { technique : Technique, origin : Maybe Technique, id : Strin type AgentValue = Value String | Variable (List AgentValue) -type Constraint = - AllowEmpty Bool - | AllowWhiteSpace Bool - | MaxLength Int - | MinLength Int - | MatchRegex String - | NotMatchRegex String - | Select (List String) +type alias Constraint = + { allowEmpty : Maybe Bool + , allowWhiteSpace: Maybe Bool + , maxLength: Maybe Int + , minLength: Maybe Int + , matchRegex: Maybe String + , notMatchRegex: Maybe String + , select: Maybe (List String) + } + +defaultConstraint = Constraint Nothing Nothing Nothing Nothing Nothing Nothing Nothing type alias MethodParameter = { name : ParameterId , description : String , type_ : String - , constraints : List Constraint + , constraints : Constraint } type Agent = Cfengine | Dsc @@ -112,12 +115,15 @@ type alias CallParameter = , value : List AgentValue } +type ParameterType = StringParameter | SelectParameter (List String) + type alias TechniqueParameter = { id : ParameterId , name : String , description : String , documentation : Maybe String , mayBeEmpty : Bool + , constraints : Constraint } type alias TechniqueCategory = @@ -217,7 +223,6 @@ type alias TechniqueUiInfo = , nameState : ValidationState TechniqueNameError , idState : ValidationState TechniqueIdError , enableDragDrop : Maybe CallId - } type alias TechniqueEditInfo = diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/JsonDecoder.elm b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/JsonDecoder.elm index 115ff76fd44..7864e20ea22 100755 --- a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/JsonDecoder.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/JsonDecoder.elm @@ -25,8 +25,9 @@ decodeTechniqueParameter = |> required "id" (map ParameterId string) |> required "name" string |> required "description" string - |> optional "documentation" (maybe string) Nothing + |> required "documentation" (maybe string) |> optional "mayBeEmpty" bool False + |> optional "constraints" decodeConstraint defaultConstraint decodeCallParameter : List (String, List AgentValue) -> List CallParameter decodeCallParameter params = @@ -155,44 +156,16 @@ decodeAgent = _ -> fail (v ++ " is not a valid agent") ) string -decodeConstraint: Decoder (List Constraint) +decodeConstraint: Decoder Constraint decodeConstraint = - andThen ( \v -> - List.foldl (\val acc -> - case val of - ("allow_empty_string", value) -> - case decodeValue bool value of - Ok b -> andThen (\t -> succeed (AllowEmpty b :: t) ) acc - Err e-> fail (errorToString e) - ("allow_whitespace_string", value) -> - case decodeValue bool value of - Ok b -> andThen (\t -> succeed (AllowWhiteSpace b :: t) ) acc - Err e-> fail (errorToString e) - ("max_length", value) -> - case decodeValue int value of - Ok b -> andThen (\t -> succeed (MaxLength b :: t) ) acc - Err e-> fail (errorToString e) - ("min_length", value) -> - case decodeValue int value of - Ok b -> andThen (\t -> succeed (MinLength b :: t) ) acc - Err e-> fail (errorToString e) - ("regex", value) -> - case decodeValue string value of - Ok b -> andThen (\t -> succeed (MatchRegex b :: t) ) acc - Err e-> fail (errorToString e) - ("not_regex", value) -> - case decodeValue string value of - Ok b -> andThen (\t -> succeed (NotMatchRegex b :: t) ) acc - Err e-> fail (errorToString e) - ("select", value) -> - case decodeValue (list string) value of - Ok b -> andThen (\t -> succeed (Select b :: t) ) acc - Err e-> fail (errorToString e) - _ -> acc - - ) (succeed []) v - - ) (keyValuePairs value) + succeed Constraint + |> optional "allow_empty_string" (maybe bool) Nothing + |> optional "allow_whitespace_string" (maybe bool) Nothing + |> optional "max_length" (maybe int) Nothing + |> optional "min_length" (maybe int) Nothing + |> optional "regex" (maybe string) Nothing + |> optional "not_regex" (maybe string) Nothing + |> optional "select" (maybe (list string)) Nothing decodeMethodParameter: Decoder MethodParameter decodeMethodParameter = diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/JsonEncoder.elm b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/JsonEncoder.elm index 9bca102820c..a892db858be 100755 --- a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/JsonEncoder.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/JsonEncoder.elm @@ -58,20 +58,37 @@ encodeResource resource = ) ] +encodeTechniqueConstraint : Constraint -> Value +encodeTechniqueConstraint constraint = + let + allowEmpty = constraint.allowEmpty |> Maybe.map ( \v -> [ ("allow_empty_string", bool v) ]) |> Maybe.withDefault [] + allowWp = constraint.allowWhiteSpace |> Maybe.map ( \v -> [ ("allow_whitespace_string", bool v) ]) |> Maybe.withDefault [] + max = constraint.maxLength |> Maybe.map ( \v -> [ ("max_length", int v) ]) |> Maybe.withDefault [] + min = constraint.minLength |> Maybe.map ( \v -> [ ("min_length", int v) ]) |> Maybe.withDefault [] + regex = constraint.matchRegex |> Maybe.map ( \v -> [ ("regex", string v) ]) |> Maybe.withDefault [] + notRegex = constraint.notMatchRegex |> Maybe.map ( \v -> [ ("not_regex", string v) ]) |> Maybe.withDefault [] + select = constraint.select |> Maybe.map ( \v -> [ ("select", list string v) ]) |> Maybe.withDefault [] + in + object (List.concat [ allowEmpty, allowWp, max, min, regex, notRegex, select ]) + + encodeTechniqueParameters: TechniqueParameter -> Value encodeTechniqueParameters param = let - doc = ( case param.documentation of - Nothing -> [] - Just s -> [ ( "documentation", string s)] - ) + doc = case param.documentation of + Nothing -> [] + Just s -> [ ( "documentation", string s)] + constraint = if (param.constraints == defaultConstraint) then + [] + else + [ ("constraints", encodeTechniqueConstraint param.constraints) ] base = [ ("id" , string param.id.value) , ("name" , string (if (String.isEmpty param.name) then (canonifyString param.description) else param.name)) , ("description", string param.description) , ("mayBeEmpty" , bool param.mayBeEmpty) ] in - object (List.append base doc ) + object (List.concat [ base, doc, constraint ] ) appendPolicyMode: Maybe PolicyMode -> List (String, Value) -> Value diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/ViewMethod.elm b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/ViewMethod.elm index deae84bd4c5..8ffc17db660 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/ViewMethod.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/ViewMethod.elm @@ -47,7 +47,7 @@ getClassParameter: Method -> MethodParameter getClassParameter method = case findClassParameter method of Just p -> p - Nothing -> MethodParameter method.classParameter "" "" [] + Nothing -> MethodParameter method.classParameter "" "" defaultConstraint findClassParameter: Method -> Maybe MethodParameter findClassParameter method = @@ -57,22 +57,16 @@ parameterName: MethodParameter -> String parameterName param = String.replace "_" " " (String.Extra.toSentenceCase param.name.value) -checkMandatoryParameter: MethodParameter -> Bool -checkMandatoryParameter methodParam = - List.all (\c -> case c of - AllowEmpty bool -> not bool - _ -> True - ) methodParam.constraints showParam: Model -> MethodCall -> ValidationState MethodCallParamError -> MethodParameter -> List CallParameter -> Html Msg showParam model call state methodParam params = let displayedValue = List.Extra.find (.id >> (==) methodParam.name ) params |> Maybe.map (.value >> displayValue) |> Maybe.withDefault "" isMandatory = - if (checkMandatoryParameter methodParam) then - span [class "mandatory-param"] [text " *"] - else + if methodParam.constraints.allowEmpty |> Maybe.withDefault False then span [class "allow-empty"] [text ""] + else + span [class "mandatory-param"] [text " *"] errors = case state of InvalidState constraintErrors -> List.filterMap (\c -> case c of ConstraintError err -> @@ -125,39 +119,48 @@ accumulateValidationState validations base = (Unchanged, Unchanged) -> Unchanged ) base validations -accumulateErrorConstraint: CallParameter -> List Constraint -> ValidationState MethodCallParamError -> ValidationState MethodCallParamError +accumulateErrorConstraint: CallParameter -> Constraint -> ValidationState MethodCallParamError -> ValidationState MethodCallParamError accumulateErrorConstraint call constraints base = - accumulateValidationState (List.map (checkConstraintOnParameter call) constraints ) base + accumulateValidationState [ (checkConstraintOnParameter call constraints) ] base checkConstraintOnParameter: CallParameter -> Constraint -> ValidationState MethodCallParamError checkConstraintOnParameter call constraint = - case constraint of - AllowEmpty True -> ValidState - AllowEmpty False -> if (isEmptyValue call.value) then InvalidState [ConstraintError { id = call.id, message = ("Parameter '"++call.id.value++"' is empty")}] else ValidState - AllowWhiteSpace True -> ValidState - AllowWhiteSpace False -> case Regex.fromString "(^\\s)|(\\s$)" of - Nothing -> ValidState - Just r -> if Regex.contains r (displayValue call.value) then InvalidState [ConstraintError { id = call.id, message = ( "Parameter '"++call.id.value++"' start or end with whitespace characters" ) } ] else ValidState - MaxLength max -> if lengthValue call.value >= max then InvalidState [ConstraintError { id = call.id, message = ("Parameter '"++call.id.value++"' should be at most " ++ (String.fromInt max) ++ " long" ) } ]else ValidState - MinLength min -> if lengthValue call.value <= min then InvalidState [ConstraintError { id = call.id, message = ("Parameter '"++call.id.value++"' should be at least " ++ (String.fromInt min) ++ " long") } ] else ValidState - MatchRegex r -> case Regex.fromString r of - Nothing -> ValidState - Just regex -> if Regex.contains regex (displayValue call.value) then - ValidState - else - InvalidState [ConstraintError { id = call.id, message = ( "Parameter '" ++ call.id.value ++"' should match the following regexp: " ++ r )} ] - NotMatchRegex r -> case Regex.fromString r of - Nothing -> ValidState + let + checkEmpty = if not (constraint.allowEmpty |> Maybe.withDefault False) && isEmptyValue call.value then [ConstraintError { id = call.id, message = ("Parameter '"++call.id.value++"' is empty")}] else [] + checkWhiteSpace = + if constraint.allowWhiteSpace |> Maybe.withDefault False then + [] + else + case Regex.fromString "(^\\s)|(\\s$)" of + Nothing -> [] + Just r -> if Regex.contains r (displayValue call.value) then [ConstraintError { id = call.id, message = ( "Parameter '"++call.id.value++"' start or end with whitespace characters" ) } ] else [] + + checkMax = if lengthValue call.value >= (constraint.maxLength |> Maybe.withDefault 16384) then [ConstraintError { id = call.id, message = ("Parameter '"++call.id.value++"' should be at most " ++ (String.fromInt (constraint.maxLength |> Maybe.withDefault 16384) ) ++ " long" ) } ]else [] + min = Maybe.withDefault 0 constraint.minLength + checkMin = if lengthValue call.value <= min then [ConstraintError { id = call.id, message = ("Parameter '"++call.id.value++"' should be at least " ++ (String.fromInt min) ++ " long") } ] else [] + regexValue = Maybe.map Regex.fromString constraint.matchRegex |> Maybe.Extra.join + checkRegex = case regexValue of + Nothing -> [] + Just regex -> + if Regex.contains regex (displayValue call.value) then + [] + else + [ConstraintError { id = call.id, message = ( "Parameter '" ++ call.id.value ++"' should match the following regexp: " ++ (Maybe.withDefault "" constraint.matchRegex) )} ] + nonRegexValue = Maybe.map Regex.fromString constraint.notMatchRegex |> Maybe.Extra.join + notRegexCheck = case nonRegexValue of + Nothing -> [] Just regex -> if Regex.contains regex (displayValue call.value) then - InvalidState [ConstraintError { id = call.id, message = ("Parameter '" ++ call.id.value ++"' should not match the following regexp: " ++ r ) }] + [ConstraintError { id = call.id, message = ("Parameter '" ++ call.id.value ++"' should not match the following regexp: " ++ (Maybe.withDefault "" constraint.notMatchRegex) ) }] else - ValidState - Select list -> if List.any ( (==) (displayValue call.value) ) list then - ValidState + [] + checkSelect = Maybe.map ( \ select -> if List.any ( (==) (displayValue call.value) ) select then + [] else - InvalidState [ConstraintError { id = call.id, message = ( "Parameter '" ++ call.id.value ++ "' should be one of the value from the following list: " ++ (String.join ", " list) )} ] - - + [ConstraintError { id = call.id, message = ( "Parameter '" ++ call.id.value ++ "' should be one of the value from the following list: " ++ (String.join ", " select) )} ] + ) constraint.select |> Maybe.withDefault [] + checks = [ checkEmpty, checkWhiteSpace, checkMax, checkMin, checkRegex, notRegexCheck, checkSelect ] |> List.concat + in + if List.isEmpty checks then ValidState else InvalidState checks {- DISPLAY ONE METHOD EXTENDED -} diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/ViewTechnique.elm b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/ViewTechnique.elm index 282d0dacb63..c25e308bfe9 100755 --- a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/ViewTechnique.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/ViewTechnique.elm @@ -98,7 +98,7 @@ listAllMethodWithErrorOnParameters methodCallList libMethods = let paramConstraints = case (List.head (List.filter (\p -> param.id.value == p.name.value) method.parameters)) of Just paramWithConstraints -> paramWithConstraints.constraints - _ -> [] + _ -> defaultConstraint state = accumulateErrorConstraint param paramConstraints ValidState in state diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/ViewTechniqueTabs.elm b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/ViewTechniqueTabs.elm index dc7d8c952a8..bed7e1c7ae3 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/ViewTechniqueTabs.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Editor/ViewTechniqueTabs.elm @@ -6,6 +6,8 @@ import Html.Events exposing (..) import Editor.AgentValueParser exposing (..) import Editor.DataTypes exposing (..) +import List.Extra +import Maybe.Extra import Regex import String.Extra @@ -74,6 +76,8 @@ techniqueParameter model technique param opened = ("", text "") checkboxId = ("paramRequired-" ++ param.id.value) + + constraint = param.constraints in li [] [ span [ class "border" ] [] @@ -81,7 +85,10 @@ techniqueParameter model technique param opened = div [ class "input-group form-group" ] [ input [readonly (not model.hasWriteRights), type_ "text", class ("form-control " ++ invalidNameClass), value param.description, placeholder "Parameter name", onInput (\s -> TechniqueParameterModified param.id {param | description = s }), required True] [] , label [ class "input-group-text", for checkboxId] - [ input[type_ "checkbox", id checkboxId, checked (not param.mayBeEmpty), onCheck (\c -> (TechniqueParameterModified param.id {param | mayBeEmpty = not c }))][] + [ input[type_ "checkbox", id checkboxId, checked (not param.mayBeEmpty), onCheck (\c -> + let newConstraint = {constraint | allowEmpty = Just c} + in + (TechniqueParameterModified param.id {param | mayBeEmpty = not c, constraints = newConstraint }))][] , span [][text " Required "] , span [ class "cursor-help popover-bs", attribute "data-toggle" "popover" @@ -100,6 +107,46 @@ techniqueParameter model technique param opened = ] ] , invalidParamElem + , div [ class "input-group" ] [ + label [ class "input-group-text", for "param_select"] + [ input[type_ "checkbox", id "param_select", checked (Maybe.Extra.isJust constraint.select ), onCheck (\c -> + let newConstraint = {constraint | select = if c then Just [ "" ] else Nothing } + in + (TechniqueParameterModified param.id {param | constraints = newConstraint }))][] + , span [][text " Value should be in within this list "] + ] + ] + , ( case constraint.select of + Just l -> ul [] (List.concat [ (List.indexedMap (\ index currentValue -> + li[] [div [ class "input-group" ] [ + input [type_ "text", class ("form-control "), value currentValue, placeholder "Value" , + onInput (\s -> + let + newConstraint = { constraint | select = Just (List.Extra.updateAt index (always s) l ) } + in + TechniqueParameterModified param.id {param | constraints = newConstraint }), required True] [] + , button [ class "btn btn-outline-secondary clipboard", title "Remove value" , + onClick ( + let + newConstraint = { constraint | select = Just (List.Extra.removeAt index l ) } + in + TechniqueParameterModified param.id {param | constraints = newConstraint }), required True] [ + i [ class "fa fa-times" ] [] + ] + ] + ]) l ) , + [ button [ class "btn btn-outline-secondary clipboard", title "add a new value" , + onClick ( + let + newConstraint = { constraint | select = Just (List.concat [l , [ ""] ] ) } + in + TechniqueParameterModified param.id {param | constraints = newConstraint }), required True] [ + i [ class "fa fa-plus" ] [] + ] + ] + ]) + Nothing -> text "" + ) , div [] param_name , button [ class "btn btn-sm btn-outline-primary", style "margin-top" "5px" , onClick (TechniqueParameterToggle param.id)] [ text "Description "