diff --git a/src/elm/Components/Form.elm b/src/elm/Components/Form.elm index 7b9df32ae..7ce8cb580 100644 --- a/src/elm/Components/Form.elm +++ b/src/elm/Components/Form.elm @@ -90,9 +90,12 @@ viewInput : , wrap_ : Maybe String , msg : String -> msg , disabled_ : Bool + , min : Maybe String + , max : Maybe String + , required : Bool } -> Html msg -viewInput { id_, title, subtitle, val, placeholder_, classList_, wrapperClassList, rows_, wrap_, msg, disabled_ } = +viewInput { id_, title, subtitle, val, placeholder_, classList_, wrapperClassList, rows_, wrap_, msg, disabled_, min, max, required} = let target = String.join "-" [ "input", id_ ] @@ -110,6 +113,9 @@ viewInput { id_, title, subtitle, val, placeholder_, classList_, wrapperClassLis , Maybe.Extra.unwrap Util.attrNone wrap wrap_ , onInput msg , disabled disabled_ + , Maybe.Extra.unwrap Util.attrNone Html.Attributes.min min + , Maybe.Extra.unwrap Util.attrNone Html.Attributes.max max + , Html.Attributes.required required , Util.testAttribute target ] [] @@ -148,9 +154,10 @@ viewNumberInput : , disabled_ : Bool , min : Maybe Int , max : Maybe Int + , required : Bool } -> Html msg -viewNumberInput { id_, title, subtitle, val, placeholder_, wrapperClassList, classList_, rows_, wrap_, msg, disabled_, min, max } = +viewNumberInput { id_, title, subtitle, val, placeholder_, wrapperClassList, classList_, rows_, wrap_, msg, disabled_, min, max, required } = let target = String.join "-" [ "input", id_ ] @@ -171,6 +178,7 @@ viewNumberInput { id_, title, subtitle, val, placeholder_, wrapperClassList, cla , Maybe.Extra.unwrap Util.attrNone wrap wrap_ , onInput msg , disabled disabled_ + , Html.Attributes.required required , Util.testAttribute target ] [] @@ -266,17 +274,19 @@ viewCheckbox : , subtitle : Maybe (Html msg) , field : String , state : Bool + , wrapperClassList : List ( String, Bool ) , msg : Bool -> msg , disabled_ : Bool } -> Html msg -viewCheckbox { id_, title, subtitle, field, state, msg, disabled_ } = +viewCheckbox { id_, title, subtitle, field, state, wrapperClassList, msg, disabled_ } = let target = String.join "-" [ "checkbox", id_, field ] in div [ class "form-control" + , classList wrapperClassList , Util.testAttribute target ] [ input @@ -397,6 +407,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_push_branch" , state = allowEvents.push.branch + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.PushBranch } , disabled_ = False , id_ = "allow-events-push-branch" @@ -406,6 +417,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_push_tag" , state = allowEvents.push.tag + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.PushTag } , disabled_ = False , id_ = "allow-events-push-tag" @@ -418,6 +430,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_pull_opened" , state = allowEvents.pull.opened + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.PullOpened } , disabled_ = False , id_ = "allow-events-pull-opened" @@ -427,6 +440,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_pull_synchronize" , state = allowEvents.pull.synchronize + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.PullSynchronize } , disabled_ = False , id_ = "allow-events-pull-synchronize" @@ -436,6 +450,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_pull_edited" , state = allowEvents.pull.edited + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.PullEdited } , disabled_ = False , id_ = "allow-events-pull-edited" @@ -445,6 +460,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_pull_reopened" , state = allowEvents.pull.reopened + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.PullReopened } , disabled_ = False , id_ = "allow-events-pull-reopened" @@ -454,6 +470,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_pull_labeled" , state = allowEvents.pull.labeled + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.PullLabeled } , disabled_ = False , id_ = "allow-events-pull-labeled" @@ -463,6 +480,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_pull_unlabeled" , state = allowEvents.pull.unlabeled + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.PullUnlabeled } , disabled_ = False , id_ = "allow-events-pull-unlabeled" @@ -475,6 +493,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_deploy_created" , state = allowEvents.deploy.created + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.DeployCreated } , disabled_ = False , id_ = "allow-events-deploy-created" @@ -487,6 +506,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_comment_created" , state = allowEvents.comment.created + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.CommentCreated } , disabled_ = False , id_ = "allow-events-comment-created" @@ -496,6 +516,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_comment_edited" , state = allowEvents.comment.edited + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.CommentEdited } , disabled_ = False , id_ = "allow-events-comment-edited" @@ -508,6 +529,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_push_delete_branch" , state = allowEvents.push.deleteBranch + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.PushDeleteBranch } , disabled_ = False , id_ = "allow-events-push-delete-branch" @@ -517,6 +539,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_push_delete_tag" , state = allowEvents.push.deleteTag + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.PushDeleteTag } , disabled_ = False , id_ = "allow-events-push-delete-tag" @@ -529,6 +552,7 @@ viewAllowEvents shared { msg, allowEvents } = , subtitle = Nothing , field = "allow_schedule_run" , state = allowEvents.schedule.run + , wrapperClassList = [] , msg = msg { allowEvents = allowEvents, event = Vela.ScheduleRun } , disabled_ = False , id_ = "allow-events-schedule-run" @@ -595,6 +619,9 @@ viewEditableList props = , wrap_ = Nothing , msg = addProps.addOnInputMsg , disabled_ = False + , min = Nothing + , max = Nothing + , required = False } , viewButton { id_ = target ++ "-add" @@ -675,6 +702,9 @@ viewEditableListItem props item = , wrap_ = Nothing , msg = props.itemEditOnInputMsg { id = itemId } , disabled_ = False + , min = Nothing + , max = Nothing + , required = False } Nothing -> diff --git a/src/elm/Pages/Admin/Settings.elm b/src/elm/Pages/Admin/Settings.elm index 04d4bcc43..4874111c9 100644 --- a/src/elm/Pages/Admin/Settings.elm +++ b/src/elm/Pages/Admin/Settings.elm @@ -848,6 +848,9 @@ view shared route model = , wrap_ = Nothing , msg = CloneImageOnInput , disabled_ = False + , min = Nothing + , max = Nothing + , required = False } , Components.Form.viewButton { id_ = cloneImageHtmlId ++ "-update" @@ -892,6 +895,7 @@ view shared route model = , disabled_ = False , min = Just starlarkExecLimitMin , max = Just <| starlarkExecLimitMax shared + , required = False } , Components.Form.viewButton { id_ = starlarkExecLimitHtmlId ++ "-update" @@ -942,6 +946,7 @@ view shared route model = , disabled_ = False , min = Just templateDepthLimitMin , max = Just templateDepthLimitMax + , required = False } , Components.Form.viewButton { id_ = "template-depth-update" diff --git a/src/elm/Pages/Org_/Repo_/Deployments/Add.elm b/src/elm/Pages/Org_/Repo_/Deployments/Add.elm index ba2825bf8..a2657617f 100644 --- a/src/elm/Pages/Org_/Repo_/Deployments/Add.elm +++ b/src/elm/Pages/Org_/Repo_/Deployments/Add.elm @@ -31,6 +31,8 @@ import Vela exposing (defaultDeploymentPayload) import View exposing (View) import Components.Loading as Loading import Dict exposing (Dict) +import Dict exposing (empty) +import Html exposing (small) {-| page : takes user, shared model, route, and returns an add deployment page. @@ -290,7 +292,7 @@ update shared route msg model = AddConfigParameter k val -> ( { model - | configParameters = Dict.remove k model.configParameters + | configParameters = Dict.remove k model.configParameters , parameters = { key = k, value = val } :: model.parameters } , Effect.none @@ -299,11 +301,12 @@ update shared route msg model = RemoveParameter parameter -> ( { model | parameters = List.Extra.remove parameter model.parameters + , configParameters = Dict.insert parameter.key "" model.configParameters } , Effect.none ) - CfgParameterValueOnInput k val -> + CfgParameterValueOnInput k val -> ( { model | configParameters = Dict.insert k val model.configParameters } , Effect.none ) @@ -637,16 +640,184 @@ viewDeploymentConfigTarget targets current msg = viewDeploymentConfigParameter : Model -> String -> Vela.DeploymentConfigParameter -> String -> (String -> String -> Msg) -> Html.Html Msg viewDeploymentConfigParameter mdl key param current msg = + let + smallText = + if param.description == "" then + "" + else + "(" ++ param.description ++ ")" + in if param.options == [] then + case param.type_ of + Vela.Int_ -> + div[ class "config-parameters-input-section"] + [ + div [ class "config-parameters-input" ] + [ Components.Form.viewInput + { title = Nothing + , subtitle = Nothing + , id_ = "parameter-key" + , val = key + , placeholder_ = key + , classList_ = [] + , wrapperClassList = [ ( "parameter-input", True ) ] + , disabled_ = True + , rows_ = Just 2 + , wrap_ = Just "soft" + , msg = ParameterKeyOnInput + , min = Nothing + , max = Nothing + , required = False + } + , Components.Form.viewNumberInput + { title = Nothing + , subtitle = Nothing + , id_ = "parameter-value" + , val = mdl.configParameters |> Dict.get key |> Maybe.withDefault "" + , placeholder_ = "value" + , classList_ = [] + , wrapperClassList = [ ( "parameter-input-number", True ) ] + , disabled_ = False + , rows_ = Just 2 + , wrap_ = Just "soft" + , msg = CfgParameterValueOnInput key + , min = if param.min == -1 then Nothing else Just param.min + , max = if param.max == -1 then Nothing else Just param.max + , required = param.required + } + , button + [ class "button" + , class "-outline" + , onClick <| AddConfigParameter key (Dict.get key mdl.configParameters |> Maybe.withDefault "") + , Util.testAttribute "button-parameter-add" + , disabled <| (String.length (Dict.get key mdl.configParameters |> Maybe.withDefault "")) == 0 + ] + [ text "Add" + ] + ] + , small [] + [ em [] [ text <| smallText ] ] + ] + Vela.Bool_ -> + div[ class "config-parameters-input-section" ] + [ + div [ class "config-parameters-input" ] + [ Components.Form.viewInput + { title = Nothing + , subtitle = Nothing + , id_ = "parameter-key" + , val = key + , placeholder_ = key + , classList_ = [] + , wrapperClassList = [ ( "parameter-input", True ) ] + , disabled_ = True + , rows_ = Just 2 + , wrap_ = Just "soft" + , msg = ParameterKeyOnInput + , min = Nothing + , max = Nothing + , required = False + } + , Html.select + [ class "form-control" + , id key + , Util.testAttribute "parameter-select" + , Html.Events.onInput <| CfgParameterValueOnInput key + ] + [Html.option + [ Html.Attributes.value "" + , Html.Attributes.selected <| (Dict.get key mdl.configParameters |> Maybe.withDefault "") == "" + ] + [ text "Select an option" ] + , + Html.option + [ Html.Attributes.value "true" + , Html.Attributes.selected <| (Dict.get key mdl.configParameters |> Maybe.withDefault "") == "true" + ] + [ text "true" ] + , Html.option + [ Html.Attributes.value "false" + , Html.Attributes.selected <| (Dict.get key mdl.configParameters |> Maybe.withDefault "") == "false" + ] + [ text "false" ] + ] + , button + [ class "button" + , class "-outline" + , onClick <| AddConfigParameter key (Dict.get key mdl.configParameters |> Maybe.withDefault "") + , Util.testAttribute "button-parameter-add" + , disabled <| (String.length (Dict.get key mdl.configParameters |> Maybe.withDefault "")) == 0 + ] + [ text "Add" + ] + ] + , small [] + [ em [] [ text <| smallText ] ] + ] + + + _ -> + div[ class "config-parameters-input-section" ] + [ + div [ class "config-parameters-input" ] + [ Components.Form.viewInput + { title = Nothing + , subtitle = Nothing + , id_ = "parameter-key" + , val = key + , placeholder_ = key + , classList_ = [] + , wrapperClassList = [ ( "parameter-input", True ) ] + , disabled_ = True + , rows_ = Just 2 + , wrap_ = Just "soft" + , msg = ParameterKeyOnInput + , min = Nothing + , max = Nothing + , required = False + } + , Components.Form.viewInput + { title = Nothing + , subtitle = Nothing + , id_ = "parameter-value" + , val = mdl.configParameters |> Dict.get key |> Maybe.withDefault "" + , placeholder_ = "value" + , classList_ = [] + , wrapperClassList = [ ( "parameter-input", True ) ] + , disabled_ = False + , rows_ = Just 2 + , wrap_ = Just "soft" + , msg = CfgParameterValueOnInput key + , min = if param.min == -1 then Nothing else Just (String.fromInt param.min) + , max = if param.max == -1 then Nothing else Just (String.fromInt param.max) + , required = param.required + } + , button + [ class "button" + , class "-outline" + , onClick <| AddConfigParameter key (Dict.get key mdl.configParameters |> Maybe.withDefault "") + , Util.testAttribute "button-parameter-add" + , disabled <| (String.length (Dict.get key mdl.configParameters |> Maybe.withDefault "")) == 0 + ] + [ text "Add" + ] + ] + , small [] + [ em [] [ text <| smallText ] ] + ] + else + div[ class "config-parameters-input-section" ] + [ div [ class "config-parameters-input" ] - [ Components.Form.viewInputSection + [ Components.Form.viewInput { title = Nothing , subtitle = Nothing , id_ = "parameter-key" , val = key , placeholder_ = key - , classList_ = [ ( "parameter-input", True ) ] + , classList_ = [] + , wrapperClassList = [ ( "parameter-input", True ) ] , disabled_ = True , rows_ = Just 2 , wrap_ = Just "soft" @@ -655,21 +826,28 @@ viewDeploymentConfigParameter mdl key param current msg = , max = Nothing , required = False } - , Components.Form.viewInputSection - { title = Nothing - , subtitle = Nothing - , id_ = "parameter-value" - , val = mdl.configParameters |> Dict.get key |> Maybe.withDefault "" - , placeholder_ = "value" - , classList_ = [ ( "parameter-input", True ) ] - , disabled_ = False - , rows_ = Just 2 - , wrap_ = Just "soft" - , msg = CfgParameterValueOnInput key - , min = if param.min == -1 then Nothing else Just (String.fromInt param.min) - , max = if param.max == -1 then Nothing else Just (String.fromInt param.max) - , required = param.required - } + , Html.select + [ class "form-control" + , id key + , Util.testAttribute "parameter-select" + , Html.Events.onInput <| CfgParameterValueOnInput key + ] + <| Html.option + [ Html.Attributes.value "" + , Html.Attributes.selected <| (Dict.get key mdl.configParameters |> Maybe.withDefault "") == "" + ] + [ text "Select an option" ] + :: + (List.map + (\option -> + Html.option + [ Html.Attributes.value option + , Html.Attributes.selected <| (Dict.get key mdl.configParameters |> Maybe.withDefault "") == option + ] + [ text option ] + ) + param.options + ) , button [ class "button" , class "-outline" @@ -680,21 +858,6 @@ viewDeploymentConfigParameter mdl key param current msg = [ text "Add" ] ] - else - div [ class "parameters-inputs" ] - [Components.Form.viewInputSection - { title = Nothing - , subtitle = Nothing - , id_ = "parameter-key" - , val = key - , placeholder_ = "key" - , classList_ = [ ( "parameter-input", True ) ] - , disabled_ = False - , rows_ = Just 2 - , wrap_ = Just "soft" - , msg = ParameterKeyOnInput - , min = Nothing - , max = Nothing - , required = False - } + , small [] + [ em [] [ text <| smallText ] ] ] diff --git a/src/elm/Vela.elm b/src/elm/Vela.elm index 35784f345..f47b87d90 100644 --- a/src/elm/Vela.elm +++ b/src/elm/Vela.elm @@ -12,6 +12,7 @@ module Vela exposing , BuildGraphInteraction , BuildGraphNode , BuildNumber + , ConfigParameterType(..) , Dashboard , DashboardRepoCard , Deployment @@ -1973,10 +1974,43 @@ decodeDeploymentConfig = |> optional "targets" (Json.Decode.list Json.Decode.string) [] |> optional "parameters" (Json.Decode.dict decodeDeploymentConfigParameter) Dict.empty +type ConfigParameterType = + String_ | + Int_ | + Bool_ + +deployConfigTypeDecoder : Decoder ConfigParameterType +deployConfigTypeDecoder = + string |> andThen toDeployConfigTypeDecoder + + +toDeployConfigTypeDecoder : String -> Decoder ConfigParameterType +toDeployConfigTypeDecoder type_ = + case type_ of + "integer" -> + succeed Int_ + + "int" -> + succeed Int_ + + "number" -> + succeed Int_ + + "boolean" -> + succeed Bool_ + + "bool" -> + succeed Bool_ + + "string" -> + succeed String_ + + _ -> + Json.Decode.fail "unrecognized secret type" type alias DeploymentConfigParameter = { description : String - , type_ : String + , type_ : ConfigParameterType , required : Bool , options : List String , min : Int @@ -1988,7 +2022,7 @@ decodeDeploymentConfigParameter : Decoder DeploymentConfigParameter decodeDeploymentConfigParameter = Json.Decode.succeed DeploymentConfigParameter |> optional "description" string "" - |> optional "type" string "string" + |> optional "type" deployConfigTypeDecoder String_ |> optional "required" bool False |> optional "options" (Json.Decode.list Json.Decode.string) [] |> optional "min" int 0 diff --git a/src/scss/_forms.scss b/src/scss/_forms.scss index af77d96d0..875c87133 100644 --- a/src/scss/_forms.scss +++ b/src/scss/_forms.scss @@ -193,6 +193,7 @@ } // focus styles +.form-control select:focus, .form-control [type='checkbox']:focus + .form-label::before, .form-control [type='radio']:focus + .form-label::before, .form-control input:focus:not([type='checkbox']):not([type='radio']), diff --git a/src/scss/_main.scss b/src/scss/_main.scss index 2ce6db81c..96828d058 100644 --- a/src/scss/_main.scss +++ b/src/scss/_main.scss @@ -1610,10 +1610,22 @@ details.build-toggle { margin-top: 0.2rem; } +.config-parameters-input-section { + display: flex; + flex-direction: column; + align-items: flex-start; + margin-top: 0.2rem; + margin-bottom: 2em; +} + .config-parameters-input { display: flex; flex-direction: row; width: 100%; + select { + margin-right: 1rem; + flex: 1; + } } .image-input, @@ -1621,6 +1633,14 @@ details.build-toggle { margin-right: 1rem; } +.parameter-input-number { + flex: 1; + margin-right: 1rem; + input { + flex: 1; + } +} + .images, .parameters { display: flex; @@ -1788,13 +1808,13 @@ code.shell { } } -.testing-section { - background-color: red; -} - .config-parameters-inputs { flex-direction: column; align-items: flex-start; margin-top: .2rem; - display: flex; +} + +select { + background-color: var(--color-bg-dark); + color: var(--color-text); }