diff --git a/docker-compose.yml b/docker-compose.yml index c7c386809..49117557c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,7 @@ services: ui: build: context: . - dockerfile: Dockerfile.local + dockerfile: ${VELA_UI_DOCKERFILE:-Dockerfile} container_name: ui image: ui:local networks: @@ -34,7 +34,7 @@ services: # https://go-vela.github.io/docs/administration/server/ server: container_name: server - image: target/vela-server:latest + image: server:local networks: - vela environment: diff --git a/src/elm/Api/Endpoint.elm b/src/elm/Api/Endpoint.elm index c2dbe343d..add7e8643 100644 --- a/src/elm/Api/Endpoint.elm +++ b/src/elm/Api/Endpoint.elm @@ -28,6 +28,7 @@ type Endpoint | Dashboard String | Dashboards | Deployment Vela.Org Vela.Repo (Maybe String) + | DeploymentConfig Vela.Org Vela.Repo (Maybe Vela.Ref) | Deployments (Maybe Pagination.Page) (Maybe Pagination.PerPage) Vela.Org Vela.Repo | Token | Repositories (Maybe Pagination.Page) (Maybe Pagination.PerPage) @@ -162,6 +163,14 @@ toUrl api endpoint = Nothing -> url api [ "deployments", org, repo ] [] + DeploymentConfig org repo maybeRef -> + case maybeRef of + Nothing -> + url api [ "deployments", org, repo, "config" ] [] + + Just ref -> + url api [ "deployments", org, repo, "config" ] [ UB.string "ref" ref ] + Deployments maybePage maybePerPage org repo -> url api [ "deployments", org, repo ] <| Pagination.toQueryParams maybePage maybePerPage diff --git a/src/elm/Api/Operations.elm b/src/elm/Api/Operations.elm index 31c950f39..af33c3e76 100644 --- a/src/elm/Api/Operations.elm +++ b/src/elm/Api/Operations.elm @@ -32,6 +32,7 @@ module Api.Operations exposing , getCurrentUser , getDashboard , getDashboards + , getDeploymentConfig , getOrgBuilds , getOrgRepos , getOrgSecret @@ -467,6 +468,29 @@ addDeployment baseUrl session options = |> withAuth session +{-| getDeploymentConfig : retrieves deployment config for a repo and pipeline ref. +-} +getDeploymentConfig : + String + -> Session + -> + { a + | org : String + , repo : String + , ref : Maybe String + } + -> Request Vela.DeploymentConfig +getDeploymentConfig baseUrl session options = + get baseUrl + (Api.Endpoint.DeploymentConfig + options.org + options.repo + options.ref + ) + Vela.decodeDeploymentConfig + |> withAuth session + + {-| getRepoHooks : retrieves hooks for a repo. -} getRepoHooks : diff --git a/src/elm/Components/Form.elm b/src/elm/Components/Form.elm index 06ef90c09..4aaf351b1 100644 --- a/src/elm/Components/Form.elm +++ b/src/elm/Components/Form.elm @@ -7,11 +7,13 @@ module Components.Form exposing (EditableListForm, handleNumberInputString, view import Components.Loading import Dict exposing (Dict) +import Effect exposing (Effect) import FeatherIcons import Html exposing (Html, button, div, h3, input, label, li, section, span, strong, text, textarea, ul) import Html.Attributes exposing (attribute, checked, class, classList, disabled, for, id, placeholder, rows, type_, value, wrap) import Html.Events exposing (onCheck, onClick, onInput) import Http +import Json.Decode import Maybe.Extra import RemoteData exposing (WebData) import Shared @@ -36,9 +38,12 @@ viewInputSection : , wrap_ : Maybe String , msg : String -> msg , disabled_ : Bool + , min : Maybe String + , max : Maybe String + , required : Bool } -> Html msg -viewInputSection { id_, title, subtitle, val, placeholder_, classList_, rows_, wrap_, msg, disabled_ } = +viewInputSection { id_, title, subtitle, val, placeholder_, classList_, rows_, wrap_, msg, disabled_, min, max, required } = let target = String.join "-" [ "input", id_ ] @@ -62,6 +67,9 @@ viewInputSection { id_, title, subtitle, val, placeholder_, classList_, rows_, w , 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 ] [] @@ -82,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_ ] @@ -102,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 ] [] @@ -140,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_ ] @@ -163,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 ] [] @@ -182,9 +198,10 @@ viewTextareaSection : , wrap_ : Maybe String , msg : String -> msg , disabled_ : Bool + , focusOutFunc : Maybe msg } -> Html msg -viewTextareaSection { id_, title, subtitle, val, placeholder_, classList_, rows_, wrap_, msg, disabled_ } = +viewTextareaSection { id_, title, subtitle, val, placeholder_, classList_, rows_, wrap_, msg, disabled_, focusOutFunc } = let target = String.join "-" [ "textarea", id_ ] @@ -208,6 +225,7 @@ viewTextareaSection { id_, title, subtitle, val, placeholder_, classList_, rows_ , Maybe.Extra.unwrap Util.attrNone wrap wrap_ , onInput msg , disabled disabled_ + , Maybe.Extra.unwrap Util.attrNone (Html.Events.on "focusout" << Json.Decode.succeed) focusOutFunc , Util.testAttribute target ] [] @@ -256,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 @@ -387,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" @@ -396,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" @@ -408,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" @@ -417,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" @@ -426,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" @@ -435,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" @@ -444,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" @@ -453,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" @@ -465,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" @@ -477,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" @@ -486,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" @@ -498,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" @@ -507,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" @@ -519,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" @@ -585,6 +619,9 @@ viewEditableList props = , wrap_ = Nothing , msg = addProps.addOnInputMsg , disabled_ = False + , min = Nothing + , max = Nothing + , required = False } , viewButton { id_ = target ++ "-add" @@ -665,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/Components/SecretForm.elm b/src/elm/Components/SecretForm.elm index 589aa4650..082d6429e 100644 --- a/src/elm/Components/SecretForm.elm +++ b/src/elm/Components/SecretForm.elm @@ -150,6 +150,9 @@ viewImagesInput { onInput_, addImage, removeImage, images, imageValue, disabled_ , wrap_ = Just "soft" , msg = onInput_ , disabled_ = disabled_ + , min = Nothing + , max = Nothing + , required = False } , button [ class "button" diff --git a/src/elm/Effect.elm b/src/elm/Effect.elm index af7bc7817..cd0c35e20 100644 --- a/src/elm/Effect.elm +++ b/src/elm/Effect.elm @@ -9,7 +9,7 @@ module Effect exposing , sendCmd, sendMsg , pushRoute, replaceRoute, loadExternalUrl , map, toCmd - , addAlertError, addAlertSuccess, addDeployment, addFavorites, addOrgSecret, addRepoSchedule, addRepoSecret, addSharedSecret, alertsUpdate, approveBuild, cancelBuild, chownRepo, clearRedirect, deleteOrgSecret, deleteRepoSchedule, deleteRepoSecret, deleteSharedSecret, disableRepo, downloadFile, enableRepo, expandPipelineConfig, finishAuthentication, focusOn, getAllBuildServices, getAllBuildSteps, getAllBuilds, getBuild, getBuildGraph, getBuildServiceLog, getBuildServices, getBuildStepLog, getBuildSteps, getCurrentUser, getCurrentUserShared, getDashboard, getDashboards, getOrgBuilds, getOrgRepos, getOrgSecret, getOrgSecrets, getPipelineConfig, getPipelineTemplates, getRepo, getRepoBuilds, getRepoBuildsShared, getRepoDeployments, getRepoHooks, getRepoHooksShared, getRepoSchedule, getRepoSchedules, getRepoSecret, getRepoSecrets, getSettings, getSharedSecret, getSharedSecrets, getWorkers, handleHttpError, logout, pushPath, redeliverHook, repairRepo, replacePath, replaceRouteRemoveTabHistorySkipDomFocus, restartBuild, setRedirect, setTheme, updateFavicon, updateFavorite, updateOrgSecret, updateRepo, updateRepoHooksShared, updateRepoSchedule, updateRepoSecret, updateSettings, updateSharedSecret, updateSourceReposShared + , addAlertError, addAlertSuccess, addDeployment, addFavorites, addOrgSecret, addRepoSchedule, addRepoSecret, addSharedSecret, alertsUpdate, approveBuild, cancelBuild, chownRepo, clearRedirect, deleteOrgSecret, deleteRepoSchedule, deleteRepoSecret, deleteSharedSecret, disableRepo, downloadFile, enableRepo, expandPipelineConfig, finishAuthentication, focusOn, getAllBuildServices, getAllBuildSteps, getAllBuilds, getBuild, getBuildGraph, getBuildServiceLog, getBuildServices, getBuildStepLog, getBuildSteps, getCurrentUser, getCurrentUserShared, getDashboard, getDashboards, getDeploymentConfig, getOrgBuilds, getOrgRepos, getOrgSecret, getOrgSecrets, getPipelineConfig, getPipelineTemplates, getRepo, getRepoBuilds, getRepoBuildsShared, getRepoDeployments, getRepoHooks, getRepoHooksShared, getRepoSchedule, getRepoSchedules, getRepoSecret, getRepoSecrets, getSettings, getSharedSecret, getSharedSecrets, getWorkers, handleHttpError, logout, pushPath, redeliverHook, repairRepo, replacePath, replaceRouteRemoveTabHistorySkipDomFocus, restartBuild, setRedirect, setTheme, updateFavicon, updateFavorite, updateOrgSecret, updateRepo, updateRepoHooksShared, updateRepoSchedule, updateRepoSecret, updateSettings, updateSharedSecret, updateSourceReposShared ) {-| @@ -594,6 +594,26 @@ addDeployment options = |> sendCmd +getDeploymentConfig : + { baseUrl : String + , session : Auth.Session.Session + , onResponse : Result (Http.Detailed.Error String) ( Http.Metadata, Vela.DeploymentConfig ) -> msg + , ref : Maybe String + , org : String + , repo : String + } + -> Effect msg +getDeploymentConfig options = + Api.try + options.onResponse + (Api.Operations.getDeploymentConfig + options.baseUrl + options.session + options + ) + |> sendCmd + + getRepoHooks : { baseUrl : String , session : Auth.Session.Session 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/Dash/Secrets/Engine_/Org/Org_/Add.elm b/src/elm/Pages/Dash/Secrets/Engine_/Org/Org_/Add.elm index 637510f15..be63e8bce 100644 --- a/src/elm/Pages/Dash/Secrets/Engine_/Org/Org_/Add.elm +++ b/src/elm/Pages/Dash/Secrets/Engine_/Org/Org_/Add.elm @@ -286,6 +286,9 @@ view shared route model = , wrap_ = Nothing , msg = NameOnInput , disabled_ = False + , min = Nothing + , max = Nothing + , required = False } , Components.Form.viewTextareaSection { title = Just "Value" @@ -298,6 +301,7 @@ view shared route model = , wrap_ = Just "soft" , msg = ValueOnInput , disabled_ = False + , focusOutFunc = Nothing } , Components.SecretForm.viewAllowEventsSelect shared diff --git a/src/elm/Pages/Dash/Secrets/Engine_/Org/Org_/Name_.elm b/src/elm/Pages/Dash/Secrets/Engine_/Org/Org_/Name_.elm index ac8ee310f..7e72230a7 100644 --- a/src/elm/Pages/Dash/Secrets/Engine_/Org/Org_/Name_.elm +++ b/src/elm/Pages/Dash/Secrets/Engine_/Org/Org_/Name_.elm @@ -393,6 +393,9 @@ view shared route model = , wrap_ = Nothing , msg = NameOnInput , disabled_ = True + , min = Nothing + , max = Nothing + , required = False } , Components.Form.viewTextareaSection { title = Just "Value" @@ -405,6 +408,7 @@ view shared route model = , wrap_ = Just "soft" , msg = ValueOnInput , disabled_ = not <| RemoteData.isSuccess model.secret + , focusOutFunc = Nothing } , Components.SecretForm.viewAllowEventsSelect shared diff --git a/src/elm/Pages/Dash/Secrets/Engine_/Repo/Org_/Repo_/Add.elm b/src/elm/Pages/Dash/Secrets/Engine_/Repo/Org_/Repo_/Add.elm index 9483ec2f7..a2788eb81 100644 --- a/src/elm/Pages/Dash/Secrets/Engine_/Repo/Org_/Repo_/Add.elm +++ b/src/elm/Pages/Dash/Secrets/Engine_/Repo/Org_/Repo_/Add.elm @@ -274,6 +274,9 @@ view shared route model = , wrap_ = Nothing , msg = NameOnInput , disabled_ = False + , min = Nothing + , max = Nothing + , required = False } , Components.Form.viewTextareaSection { title = Just "Value" @@ -286,6 +289,7 @@ view shared route model = , wrap_ = Just "soft" , msg = ValueOnInput , disabled_ = False + , focusOutFunc = Nothing } , Components.SecretForm.viewAllowEventsSelect shared diff --git a/src/elm/Pages/Dash/Secrets/Engine_/Repo/Org_/Repo_/Name_.elm b/src/elm/Pages/Dash/Secrets/Engine_/Repo/Org_/Repo_/Name_.elm index 494d15b6e..001c9cd4f 100644 --- a/src/elm/Pages/Dash/Secrets/Engine_/Repo/Org_/Repo_/Name_.elm +++ b/src/elm/Pages/Dash/Secrets/Engine_/Repo/Org_/Repo_/Name_.elm @@ -386,6 +386,9 @@ view shared route model = , wrap_ = Nothing , msg = \_ -> NoOp , disabled_ = True + , min = Nothing + , max = Nothing + , required = False } , Components.Form.viewTextareaSection { title = Just "Value" @@ -398,6 +401,7 @@ view shared route model = , wrap_ = Just "soft" , msg = ValueOnInput , disabled_ = not <| RemoteData.isSuccess model.secret + , focusOutFunc = Nothing } , Components.SecretForm.viewAllowEventsSelect shared diff --git a/src/elm/Pages/Dash/Secrets/Engine_/Shared/Org_/Team_/Add.elm b/src/elm/Pages/Dash/Secrets/Engine_/Shared/Org_/Team_/Add.elm index 4e1ab64dc..1ca6bf4f6 100644 --- a/src/elm/Pages/Dash/Secrets/Engine_/Shared/Org_/Team_/Add.elm +++ b/src/elm/Pages/Dash/Secrets/Engine_/Shared/Org_/Team_/Add.elm @@ -294,6 +294,9 @@ view shared route model = , wrap_ = Nothing , msg = TeamOnInput , disabled_ = False + , min = Nothing + , max = Nothing + , required = False } , Components.Form.viewInputSection { title = Just "Name" @@ -306,6 +309,9 @@ view shared route model = , wrap_ = Nothing , msg = NameOnInput , disabled_ = False + , min = Nothing + , max = Nothing + , required = False } , Components.Form.viewTextareaSection { title = Just "Value" @@ -318,6 +324,7 @@ view shared route model = , wrap_ = Just "soft" , msg = ValueOnInput , disabled_ = False + , focusOutFunc = Nothing } , Components.SecretForm.viewAllowEventsSelect shared diff --git a/src/elm/Pages/Dash/Secrets/Engine_/Shared/Org_/Team_/Name_.elm b/src/elm/Pages/Dash/Secrets/Engine_/Shared/Org_/Team_/Name_.elm index 143636f9c..0ebd7915b 100644 --- a/src/elm/Pages/Dash/Secrets/Engine_/Shared/Org_/Team_/Name_.elm +++ b/src/elm/Pages/Dash/Secrets/Engine_/Shared/Org_/Team_/Name_.elm @@ -385,6 +385,9 @@ view shared route model = , wrap_ = Nothing , msg = \_ -> NoOp , disabled_ = True + , min = Nothing + , max = Nothing + , required = False } , Components.Form.viewTextareaSection { title = Just "Value" @@ -397,6 +400,7 @@ view shared route model = , wrap_ = Just "soft" , msg = ValueOnInput , disabled_ = not <| RemoteData.isSuccess model.secret + , focusOutFunc = Nothing } , Components.SecretForm.viewAllowEventsSelect shared diff --git a/src/elm/Pages/Org_/Repo_/Deployments/Add.elm b/src/elm/Pages/Org_/Repo_/Deployments/Add.elm index 7ddb3c05c..2ececad6f 100644 --- a/src/elm/Pages/Org_/Repo_/Deployments/Add.elm +++ b/src/elm/Pages/Org_/Repo_/Deployments/Add.elm @@ -8,10 +8,11 @@ module Pages.Org_.Repo_.Deployments.Add exposing (Model, Msg, page, view) import Auth import Components.Crumbs import Components.Form +import Components.Loading as Loading import Components.Nav -import Dict +import Dict exposing (Dict, empty) import Effect exposing (Effect) -import Html exposing (a, button, code, div, em, h2, label, main_, p, section, span, strong, text) +import Html exposing (a, button, code, div, em, h2, label, main_, p, section, small, span, strong, text) import Html.Attributes exposing (class, disabled, for, href, id) import Html.Events exposing (onClick) import Http @@ -81,6 +82,9 @@ type alias Model = , parameterKey : String , parameterValue : String , parameters : List Vela.KeyValuePair + , config : WebData Vela.DeploymentConfig + , configParameters : Dict String String + , dropDownDict : Dict String Bool } @@ -112,14 +116,27 @@ init shared route () = Nothing ) |> List.filterMap identity + , config = RemoteData.Loading + , configParameters = Dict.empty + , dropDownDict = Dict.empty } - , Effect.getRepo - { baseUrl = shared.velaAPIBaseURL - , session = shared.session - , onResponse = GetRepoResponse - , org = route.params.org - , repo = route.params.repo - } + , Effect.batch + [ Effect.getRepo + { baseUrl = shared.velaAPIBaseURL + , session = shared.session + , onResponse = GetRepoResponse + , org = route.params.org + , repo = route.params.repo + } + , Effect.getDeploymentConfig + { baseUrl = shared.velaAPIBaseURL + , session = shared.session + , onResponse = GetDeploymentConfigResponse + , org = route.params.org + , repo = route.params.repo + , ref = Nothing + } + ] ) @@ -136,6 +153,7 @@ type Msg | GetRepoResponse (Result (Http.Detailed.Error String) ( Http.Metadata, Vela.Repository )) -- DEPLOYMENTS | AddDeploymentResponse (Result (Http.Detailed.Error String) ( Http.Metadata, Vela.Deployment )) + | GetDeploymentConfigResponse (Result (Http.Detailed.Error String) ( Http.Metadata, Vela.DeploymentConfig )) | TargetOnInput String | RefOnInput String | DescriptionOnInput String @@ -144,6 +162,10 @@ type Msg | ParameterValueOnInput String | AddParameter | RemoveParameter Vela.KeyValuePair + | CfgParameterValueOnInput String String + | UpdateRef + | AddConfigParameter String String + | ToggleDropdown String | SubmitForm @@ -204,6 +226,33 @@ update shared route msg model = } ) + GetDeploymentConfigResponse response -> + case response of + Ok ( _, config ) -> + ( { model + | config = RemoteData.succeed config + , configParameters = Dict.fromList <| List.map (\( k, _ ) -> ( k, "" )) (Dict.toList config.parameters) + , dropDownDict = Dict.fromList <| List.map (\( k, _ ) -> ( k, False )) (Dict.toList config.parameters) + } + , if List.length config.targets > 0 then + Effect.addAlertSuccess + { content = "Found dynamic parameters for this deployment ref!" + , addToastIfUnique = True + , link = Nothing + } + + else + Effect.none + ) + + Err error -> + ( model + , Effect.handleHttpError + { error = error + , shouldShowAlertFn = Errors.showAlertAlways + } + ) + TargetOnInput val -> ( { model | target = val } , Effect.none @@ -243,19 +292,53 @@ update shared route msg model = , Effect.none ) + AddConfigParameter k val -> + ( { model + | configParameters = Dict.remove k model.configParameters + , parameters = { key = k, value = val } :: model.parameters + } + , Effect.none + ) + RemoveParameter parameter -> ( { model | parameters = List.Extra.remove parameter model.parameters + , configParameters = Dict.insert parameter.key "" model.configParameters + , dropDownDict = Dict.update parameter.key (\_ -> Just False) model.dropDownDict } , Effect.none ) + CfgParameterValueOnInput k val -> + ( { model + | configParameters = Dict.insert k val model.configParameters + , dropDownDict = Dict.update k (\_ -> Just False) model.dropDownDict + } + , Effect.none + ) + + UpdateRef -> + ( model + , Effect.getDeploymentConfig + { baseUrl = shared.velaAPIBaseURL + , session = shared.session + , onResponse = GetDeploymentConfigResponse + , org = route.params.org + , repo = route.params.repo + , ref = Just model.ref + } + ) + + ToggleDropdown key -> + ( { model | dropDownDict = Dict.update key (\val -> Just <| Maybe.withDefault True <| Maybe.map not val) model.dropDownDict } + , Effect.none + ) + SubmitForm -> let payload = { defaultDeploymentPayload | org = Just route.params.org - , repo = Just route.params.repo , commit = Nothing , description = Just model.description , ref = @@ -346,18 +429,6 @@ view shared route model = _ -> text "" - , Components.Form.viewTextareaSection - { title = Just "Target" - , subtitle = Nothing - , id_ = "target" - , val = model.target - , placeholder_ = "Provide the name for the target deployment environment (default: \"production\")" - , classList_ = [ ( "secret-value", True ) ] - , disabled_ = False - , rows_ = Just 2 - , wrap_ = Just "soft" - , msg = TargetOnInput - } , Components.Form.viewTextareaSection { title = Just "Ref" , subtitle = Nothing @@ -372,6 +443,7 @@ view shared route model = , rows_ = Just 3 , wrap_ = Just "soft" , msg = RefOnInput + , focusOutFunc = Just UpdateRef } , Components.Form.viewTextareaSection { title = Just "Description" @@ -384,7 +456,30 @@ view shared route model = , rows_ = Just 5 , wrap_ = Just "soft" , msg = DescriptionOnInput + , focusOutFunc = Nothing } + , case model.config of + RemoteData.Success config -> + if List.length config.targets > 0 then + viewDeploymentConfigTarget config.targets model.target TargetOnInput + + else + Components.Form.viewTextareaSection + { title = Just "Target" + , subtitle = Nothing + , id_ = "target" + , val = model.target + , placeholder_ = "Provide the name for the target deployment environment (default: \"production\")" + , classList_ = [ ( "secret-value", True ) ] + , disabled_ = False + , rows_ = Just 2 + , wrap_ = Just "soft" + , msg = TargetOnInput + , focusOutFunc = Nothing + } + + _ -> + Loading.viewSmallLoaderWithText "loading config..." , Components.Form.viewTextareaSection { title = Just "Task" , subtitle = Nothing @@ -396,103 +491,135 @@ view shared route model = , rows_ = Just 2 , wrap_ = Just "soft" , msg = TaskOnInput + , focusOutFunc = Nothing } - , section [] - [ div - [ id "parameter-select" - , class "form-control" - , class "-stack" - , class "parameters-container" + , div [] + [ div [ class "parameters-inputs", Util.testAttribute "parameters-list" ] + [ case model.config of + RemoteData.Success config -> + if Dict.size model.configParameters > 0 then + div + [ id "parameter-select" + , class "form-control" + , class "-stack" + , class "parameters-container" + ] + [ label + [ for "parameter-select" + , class "form-label" + ] + [ strong [] [ text "Add Config Parameters" ] + ] + , div [ class "config-parameters-inputs", Util.testAttribute "parameters-list" ] + (Dict.toList model.configParameters + |> List.concatMap + (\( key, value ) -> + case Dict.get key config.parameters of + Just param -> + [ viewDeploymentConfigParameter model key param value CfgParameterValueOnInput ] + + Nothing -> + [] + ) + ) + ] + + else + text "" + + _ -> + text "" ] - [ label - [ for "parameter-select" - , class "form-label" + , label + [ for "parameter-select" + , class "form-label" + ] + [ strong [] [ text "Add Parameters" ] + ] + , div [ class "parameters-inputs" ] + [ Components.Form.viewInputSection + { title = Nothing + , subtitle = Nothing + , id_ = "parameter-key" + , val = model.parameterKey + , placeholder_ = "key" + , classList_ = [ ( "parameter-input", True ) ] + , disabled_ = False + , rows_ = Just 2 + , wrap_ = Just "soft" + , msg = ParameterKeyOnInput + , min = Nothing + , max = Nothing + , required = False + } + , Components.Form.viewInputSection + { title = Nothing + , subtitle = Nothing + , id_ = "parameter-value" + , val = model.parameterValue + , placeholder_ = "value" + , classList_ = [ ( "parameter-input", True ) ] + , disabled_ = False + , rows_ = Just 2 + , wrap_ = Just "soft" + , msg = ParameterValueOnInput + , min = Nothing + , max = Nothing + , required = False + } + , button + [ class "button" + , class "-outline" + , onClick <| AddParameter + , Util.testAttribute "button-parameter-add" + , disabled <| String.length model.parameterKey == 0 || String.length model.parameterValue == 0 ] - [ strong [] [ text "Add Parameters" ] - , span - [ class "field-description" ] - [ em [] [ text "(Optional)" ] - ] - ] - , div [ class "parameters-inputs" ] - [ Components.Form.viewInputSection - { title = Nothing - , subtitle = Nothing - , id_ = "parameter-key" - , val = model.parameterKey - , placeholder_ = "key" - , classList_ = [ ( "parameter-input", True ) ] - , disabled_ = False - , rows_ = Just 2 - , wrap_ = Just "soft" - , msg = ParameterKeyOnInput - } - , Components.Form.viewInputSection - { title = Nothing - , subtitle = Nothing - , id_ = "parameter-value" - , val = model.parameterValue - , placeholder_ = "value" - , classList_ = [ ( "parameter-input", True ) ] - , disabled_ = False - , rows_ = Just 2 - , wrap_ = Just "soft" - , msg = ParameterValueOnInput - } - , button - [ class "button" - , class "-outline" - , onClick <| AddParameter - , Util.testAttribute "button-parameter-add" - , disabled <| String.length model.parameterKey == 0 || String.length model.parameterValue == 0 - ] - [ text "Add" - ] + [ text "Add" ] ] - , div [ class "parameters", Util.testAttribute "parameters-list" ] <| - if List.length model.parameters > 0 then - let - viewParameter parameter = - div [ class "parameter", class "chevron" ] - [ div [ class "name" ] [ text (parameter.key ++ "=" ++ parameter.value) ] - , button - [ class "button" - , class "-outline" - , onClick <| RemoveParameter parameter - ] - [ text "remove" - ] + ] + , div [ class "parameters", Util.testAttribute "parameters-list" ] <| + if List.length model.parameters > 0 then + let + viewParameter parameter = + div [ class "parameter", class "chevron" ] + [ div [ class "name" ] [ text (parameter.key ++ "=" ++ parameter.value) ] + , button + [ class "button" + , class "-outline" + , onClick <| RemoveParameter parameter + ] + [ text "remove" ] - in - List.map viewParameter <| List.reverse model.parameters - - else - [ div [ class "no-parameters" ] - [ div - [ class "none" ] - [ code [] [ text "no parameters defined" ] ] + in + List.map viewParameter <| List.reverse model.parameters + + else + [ div [ class "no-parameters" ] + [ div + [ class "none" ] + [ code [] [ text "no parameters defined" ] ] ] - ] - , div [ class "help" ] - [ text "Need help? Visit our " - , a - [ href <| shared.velaDocsURL ++ "/usage/deployments/" ] - [ text "docs" ] - , text "!" + ] + , div [ class "help" ] + [ text "Need help? Visit our " + , a + [ href <| shared.velaDocsURL ++ "/usage/deployments/" ] - , div [ class "buttons" ] - [ div [ class "form-action" ] - [ button - [ class "button" - , class "-outline" - , onClick SubmitForm - ] - [ text "Add Deployment" ] + [ text "docs" ] + , text "!" + ] + , div [ class "buttons" ] + [ div [ class "form-action" ] + [ button + [ class "button" + , class "-outline" + , onClick SubmitForm ] + [ text "Add Deployment" ] ] ] ] @@ -500,3 +627,296 @@ view shared route model = ] ] } + + +viewDeploymentConfigTarget : List String -> String -> (String -> Msg) -> Html.Html Msg +viewDeploymentConfigTarget targets current msg = + section [ class "settings", Util.testAttribute "repo-settings-pipeline-type" ] + [ Html.label [ class "form-label" ] [ Html.strong [] [ text "Target" ] ] + , div + [ class "form-controls", class "-stack" ] + <| + List.map + (\target -> + Components.Form.viewRadio + { value = current + , field = target + , title = target + , subtitle = Nothing + , msg = msg target + , disabled_ = False + , id_ = target + } + ) + targets + ] + + +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 + } + , div [ class "custom-select-container" ] + [ div + [ class "custom-select-selected" + , Html.Events.onClick (ToggleDropdown key) + ] + [ text (Dict.get key mdl.configParameters |> Maybe.withDefault "Select an option") ] + , div + [ class "custom-select-options" + , class <| + if Dict.get key mdl.dropDownDict |> Maybe.withDefault False then + "" + + else + "hidden" + ] + [ div + [ class "custom-select-option" + , Html.Attributes.value "True" + , Html.Events.onClick (CfgParameterValueOnInput key "True") + ] + [ text "True" ] + , div + [ class "custom-select-option" + , Html.Attributes.value "False" + , Html.Events.onClick (CfgParameterValueOnInput key "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 + let + selected = + if (Dict.get key mdl.configParameters |> Maybe.withDefault "") == "" then + "Select an option" + + else + Dict.get key mdl.configParameters |> Maybe.withDefault "" + + arrow = + if Dict.get key mdl.dropDownDict |> Maybe.withDefault False then + "▲" + + else + "▼" + in + 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 + } + , div [ class "custom-select-container" ] + [ div + [ class "custom-select-selected" + , Html.Events.onClick (ToggleDropdown key) + ] + [ text selected + , span [ class "arrow" ] [ text arrow ] + ] + , div + [ class "custom-select-options" + , class <| + if Dict.get key mdl.dropDownDict |> Maybe.withDefault False then + "" + + else + "hidden" + ] + (List.map + (\option -> + div + [ class "custom-select-option" + , Html.Attributes.value option + , Html.Events.onClick (CfgParameterValueOnInput key option) + ] + [ text option ] + ) + param.options + ) + ] + , 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 ] ] + ] diff --git a/src/elm/Pages/Org_/Repo_/Schedules/Add.elm b/src/elm/Pages/Org_/Repo_/Schedules/Add.elm index e3dfc1e86..1c9e48cb7 100644 --- a/src/elm/Pages/Org_/Repo_/Schedules/Add.elm +++ b/src/elm/Pages/Org_/Repo_/Schedules/Add.elm @@ -250,6 +250,9 @@ view shared route model = , wrap_ = Nothing , msg = NameOnInput , disabled_ = formDisabled + , min = Nothing + , max = Nothing + , required = False } , Components.Form.viewTextareaSection { title = Just "Cron Expression" @@ -262,6 +265,7 @@ view shared route model = , wrap_ = Just "soft" , msg = EntryOnInput , disabled_ = formDisabled + , focusOutFunc = Nothing } , Components.ScheduleForm.viewEnabledInput { msg = EnabledOnClick @@ -284,6 +288,9 @@ view shared route model = , wrap_ = Nothing , msg = BranchOnInput , disabled_ = formDisabled + , min = Nothing + , max = Nothing + , required = False } , Components.ScheduleForm.viewHelp shared.velaDocsURL , Components.Form.viewButton diff --git a/src/elm/Pages/Org_/Repo_/Schedules/Name_.elm b/src/elm/Pages/Org_/Repo_/Schedules/Name_.elm index 1055c7609..41c85c9e0 100644 --- a/src/elm/Pages/Org_/Repo_/Schedules/Name_.elm +++ b/src/elm/Pages/Org_/Repo_/Schedules/Name_.elm @@ -369,6 +369,9 @@ view shared route model = , wrap_ = Nothing , msg = \_ -> NoOp , disabled_ = True + , min = Nothing + , max = Nothing + , required = False } , Components.Form.viewTextareaSection { title = Just "Cron Expression" @@ -381,6 +384,7 @@ view shared route model = , wrap_ = Just "soft" , msg = EntryOnInput , disabled_ = formDisabled + , focusOutFunc = Nothing } , Components.ScheduleForm.viewEnabledInput { msg = EnabledOnClick @@ -403,6 +407,9 @@ view shared route model = , wrap_ = Nothing , msg = BranchOnInput , disabled_ = formDisabled + , min = Nothing + , max = Nothing + , required = False } , Components.ScheduleForm.viewHelp shared.velaDocsURL , div [ class "buttons" ] diff --git a/src/elm/Vela.elm b/src/elm/Vela.elm index 8f7d61f86..8ddcd0d03 100644 --- a/src/elm/Vela.elm +++ b/src/elm/Vela.elm @@ -12,9 +12,12 @@ module Vela exposing , BuildGraphInteraction , BuildGraphNode , BuildNumber + , ConfigParameterType(..) , Dashboard , DashboardRepoCard , Deployment + , DeploymentConfig + , DeploymentConfigParameter , DeploymentPayload , EnableRepoPayload , Enabled(..) @@ -61,6 +64,8 @@ module Vela exposing , decodeDashboard , decodeDashboards , decodeDeployment + , decodeDeploymentConfig + , decodeDeploymentConfigParameter , decodeDeployments , decodeGraphInteraction , decodeHooks @@ -277,10 +282,10 @@ decodeUser : Decoder User decodeUser = Json.Decode.succeed User |> required "id" int - |> required "name" string + |> optional "name" string "" |> optional "favorites" (Json.Decode.list string) [] |> optional "dashboards" (Json.Decode.list string) [] - |> required "active" bool + |> optional "active" bool False |> optional "admin" bool False @@ -1877,7 +1882,7 @@ encodeSecretPayload secret = type alias Deployment = { id : Int , number : Int - , repo_id : Int + , repo : Repository , url : String , created_by : String , created_at : Int @@ -1896,7 +1901,7 @@ decodeDeployment = Json.Decode.succeed Deployment |> optional "id" int -1 |> optional "number" int -1 - |> optional "repo_id" int -1 + |> optional "repo" decodeRepository emptyRepository |> optional "url" string "" |> optional "created_by" string "" |> optional "created_at" int 0 @@ -1916,7 +1921,6 @@ decodeDeployments = type alias DeploymentPayload = { org : Maybe String - , repo : Maybe String , commit : Maybe String , description : Maybe String , ref : Maybe String @@ -1929,7 +1933,6 @@ type alias DeploymentPayload = defaultDeploymentPayload : DeploymentPayload defaultDeploymentPayload = { org = Nothing - , repo = Nothing , commit = Nothing , description = Nothing , ref = Nothing @@ -1943,7 +1946,6 @@ encodeDeploymentPayload : DeploymentPayload -> Json.Encode.Value encodeDeploymentPayload deployment = Json.Encode.object [ ( "org", encodeOptional Json.Encode.string deployment.org ) - , ( "repo", encodeOptional Json.Encode.string deployment.repo ) , ( "commit", encodeOptional Json.Encode.string deployment.commit ) , ( "description", encodeOptional Json.Encode.string deployment.description ) , ( "ref", encodeOptional Json.Encode.string deployment.ref ) @@ -1958,6 +1960,80 @@ decodeDeploymentParameters = Json.Decode.map decodeKeyValuePairs <| Json.Decode.keyValuePairs Json.Decode.string + +-- DEPLOYMENT CONFIG + + +type alias DeploymentConfig = + { targets : List String + , parameters : Dict String DeploymentConfigParameter + } + + +decodeDeploymentConfig : Decoder DeploymentConfig +decodeDeploymentConfig = + Json.Decode.succeed DeploymentConfig + |> 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_ : ConfigParameterType + , required : Bool + , options : List String + , min : Int + , max : Int + } + + +decodeDeploymentConfigParameter : Decoder DeploymentConfigParameter +decodeDeploymentConfigParameter = + Json.Decode.succeed DeploymentConfigParameter + |> optional "description" string "" + |> optional "type" deployConfigTypeDecoder String_ + |> optional "required" bool False + |> optional "options" (Json.Decode.list Json.Decode.string) [] + |> optional "min" int 0 + |> optional "max" int 0 + + type alias Worker = { id : Int , host_name : String 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 161127bad..8fb7ec4f9 100644 --- a/src/scss/_main.scss +++ b/src/scss/_main.scss @@ -1610,11 +1610,39 @@ 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 { + flex: 1; + margin-right: 1rem; + } +} + .image-input, .parameter-input { margin-right: 1rem; } +.parameter-input-number { + flex: 1; + margin-right: 1rem; + + input { + flex: 1; + } +} + .images, .parameters { display: flex; @@ -1781,3 +1809,65 @@ code.shell { content: '$'; } } + +.config-parameters-inputs { + flex-direction: column; + align-items: flex-start; + margin-top: 0.2rem; +} + +select { + color: var(--color-text); + + background-color: var(--color-bg-dark); +} + +.custom-select-container { + flex: 1; + margin-right: 1rem; +} + +.custom-select-selected { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px; + + background-color: var(--color-bg-dark); + border: 1px solid var(--color-bg-light); + cursor: pointer; +} + +.custom-select-selected .arrow { + margin-left: 10px; +} + +.custom-select-options { + position: absolute; + z-index: 1; + + display: none; + width: 75%; + + background-color: var(--color-bg-dark); + border: 1px solid var(--color-bg-light); +} + +.custom-select-options .custom-select-option { + padding: 10px; + + cursor: pointer; +} + +.custom-select-options .custom-select-option:hover, +.custom-select-options .custom-select-option:focus { + background-color: var(--color-bg-light); +} + +.custom-select-options.hidden { + display: none; +} + +.custom-select-container .custom-select-options:not(.hidden) { + display: block; +}