diff --git a/src/elm/Api/Operations_.elm b/src/elm/Api/Operations_.elm index 0925b0d73..b3668c293 100644 --- a/src/elm/Api/Operations_.elm +++ b/src/elm/Api/Operations_.elm @@ -128,15 +128,15 @@ getOrgRepos baseUrl session { org } = {-| getRepoBuilds : retrieves builds for a repo -} -getRepoBuilds : String -> Session -> { a | org : String, repo : String } -> Request (List Vela.Build) -getRepoBuilds baseUrl session { org, repo } = - get baseUrl (Endpoint.Builds Nothing Nothing Nothing org repo) Vela.decodeBuilds +getRepoBuilds : String -> Session -> { a | org : String, repo : String, pageNumber : Maybe Int, perPage : Maybe Int, maybeEvent : Maybe String } -> Request (List Vela.Build) +getRepoBuilds baseUrl session options = + get baseUrl (Endpoint.Builds options.pageNumber options.perPage options.maybeEvent options.org options.repo) Vela.decodeBuilds |> withAuth session {-| getRepoDeployments : retrieves deployments for a repo -} -getRepoDeployments : String -> Session -> { a | org : String, repo : String } -> Request (List Vela.Deployment) -getRepoDeployments baseUrl session { org, repo } = - get baseUrl (Endpoint.Deployments Nothing Nothing org repo) Vela.decodeDeployments +getRepoDeployments : String -> Session -> { a | org : String, repo : String, pageNumber : Maybe Int, perPage : Maybe Int } -> Request (List Vela.Deployment) +getRepoDeployments baseUrl session options = + get baseUrl (Endpoint.Deployments options.pageNumber options.perPage options.org options.repo) Vela.decodeDeployments |> withAuth session diff --git a/src/elm/Auth.elm b/src/elm/Auth.elm index c1902da94..2309b1e49 100644 --- a/src/elm/Auth.elm +++ b/src/elm/Auth.elm @@ -10,6 +10,7 @@ import Auth.Session exposing (Session(..)) import Dict import Route exposing (Route) import Route.Path +import Route.Query import Shared import View exposing (View) @@ -34,8 +35,7 @@ onPageLoad shared route = { path = Route.Path.Login_ , query = Dict.fromList - [ ( "from", route.url.path ) - ] + [ ( "from", Route.toString route ) ] , hash = Nothing } diff --git a/src/elm/Components/Builds.elm b/src/elm/Components/Builds.elm index 1ac8fdaab..88b4d8552 100644 --- a/src/elm/Components/Builds.elm +++ b/src/elm/Components/Builds.elm @@ -1,21 +1,49 @@ -module Components.Builds exposing (view, viewPreview) +module Components.Builds exposing (view, viewHeader) import Ansi import Ansi.Log import Components.Svgs as SvgBuilder exposing (buildStatusToIcon) import DateFormat.Relative exposing (relativeTime) import FeatherIcons -import Html exposing (Html, a, br, code, details, div, em, h1, li, ol, p, span, strong, summary, table, td, text, tr, ul) +import Html + exposing + ( Html + , a + , br + , code + , details + , div + , em + , h1 + , input + , label + , li + , ol + , p + , span + , strong + , summary + , table + , td + , text + , tr + , ul + ) import Html.Attributes exposing ( attribute + , checked , class , classList + , for , href , id + , name , style , title + , type_ ) +import Html.Events exposing (onClick) import List.Extra import Pages.Build.Model exposing @@ -714,3 +742,73 @@ colorClassesAnsi suffix bold mc = Just Ansi.BrightWhite -> [ brightPrefix ++ "white" ++ suffix ] + + +viewHeader : + { maybeEvent : Maybe String + , showFullTimestamps : Bool + , filterByEvent : Maybe String -> msg + , showHideFullTimestamps : msg + } + -> Html msg +viewHeader props = + div [ class "build-bar" ] + [ viewFilter props.maybeEvent props.filterByEvent + , viewTimeToggle props.showFullTimestamps props.showHideFullTimestamps + ] + + +viewFilter : Maybe String -> (Maybe String -> msg) -> Html msg +viewFilter maybeEvent filterByEventMsg = + let + eventToMaybe event = + case event of + "all" -> + Nothing + + _ -> + Just event + + eventEnum = + [ "all" + , "push" + , "pull_request" + , "tag" + , "deployment" + , "schedule" + , "comment" + ] + in + div [ class "form-controls", class "build-filters", Util.testAttribute "build-filter" ] <| + div [] [ text "Filter by Event:" ] + :: List.map + (\e -> + div [ class "form-control" ] + [ input + [ type_ "radio" + , id <| "filter-" ++ e + , name "build-filter" + , Util.testAttribute <| "build-filter-" ++ e + , checked <| maybeEvent == eventToMaybe e + , onClick <| filterByEventMsg (eventToMaybe e) + , attribute "aria-label" <| "filter to show " ++ e ++ " events" + ] + [] + , label + [ class "form-label" + , for <| "filter-" ++ e + ] + [ text <| String.replace "_" " " e ] + ] + ) + eventEnum + + +viewTimeToggle : Bool -> msg -> Html msg +viewTimeToggle showTimestamp showHideFullTimestampMsg = + div [ class "form-controls", class "-stack", class "time-toggle" ] + [ div [ class "form-control" ] + [ input [ type_ "checkbox", checked showTimestamp, onClick showHideFullTimestampMsg, id "checkbox-time-toggle", Util.testAttribute "time-toggle" ] [] + , label [ class "form-label", for "checkbox-time-toggle" ] [ text "show full timestamps" ] + ] + ] diff --git a/src/elm/Effect.elm b/src/elm/Effect.elm index be05759f6..f56a9c265 100644 --- a/src/elm/Effect.elm +++ b/src/elm/Effect.elm @@ -217,9 +217,9 @@ toCmd options effect = -- CUSTOM EFFECTS -setTheme : Vela.Theme -> Effect msg -setTheme theme = - SendSharedMsg <| Shared.Msg.SetTheme theme +setTheme : { theme : Vela.Theme } -> Effect msg +setTheme options = + SendSharedMsg <| Shared.Msg.SetTheme options logout : {} -> Effect msg @@ -264,6 +264,9 @@ getRepoBuilds : { baseUrl : String , session : Session , onResponse : Result (Http.Detailed.Error String) ( Http.Metadata, List Vela.Build ) -> msg + , pageNumber : Maybe Int + , perPage : Maybe Int + , maybeEvent : Maybe String , org : String , repo : String } @@ -293,6 +296,8 @@ getRepoDeployments : { baseUrl : String , session : Session , onResponse : Result (Http.Detailed.Error String) ( Http.Metadata, List Vela.Deployment ) -> msg + , pageNumber : Maybe Int + , perPage : Maybe Int , org : String , repo : String } @@ -331,4 +336,4 @@ alertsUpdate options = focusOn : { target : String } -> Effect msg focusOn options = - SendSharedMsg <| Shared.Msg.FocusOn options.target + SendSharedMsg <| Shared.Msg.FocusOn options diff --git a/src/elm/Layouts/Default.elm b/src/elm/Layouts/Default.elm index 6a9611a09..bc5fdd5a9 100644 --- a/src/elm/Layouts/Default.elm +++ b/src/elm/Layouts/Default.elm @@ -79,11 +79,11 @@ init shared _ = type Msg = NoOp - | CopyAlert String - | AlertsUpdate (Alerting.Msg Alert) - | SetTheme Theme | ShowHideIdentity (Maybe Bool) | ShowHideHelp (Maybe Bool) + | SetTheme Theme + | AlertsUpdate (Alerting.Msg Alert) + | CopyAlert String update : Msg -> Model -> ( Model, Effect Msg ) @@ -94,19 +94,6 @@ update msg model = , Effect.none ) - CopyAlert contentCopied -> - ( model - , Effect.addAlertSuccess { content = contentCopied, addToastIfUnique = False } - ) - - AlertsUpdate alert -> - ( model - , Effect.alertsUpdate { alert = alert } - ) - - SetTheme theme -> - ( model, Effect.setTheme theme ) - ShowHideIdentity show -> ( { model | showIdentity = @@ -133,6 +120,19 @@ update msg model = , Effect.none ) + SetTheme theme -> + ( model, Effect.setTheme { theme = theme } ) + + AlertsUpdate alert -> + ( model + , Effect.alertsUpdate { alert = alert } + ) + + CopyAlert contentCopied -> + ( model + , Effect.addAlertSuccess { content = contentCopied, addToastIfUnique = False } + ) + subscriptions : Model -> Sub Msg subscriptions model = diff --git a/src/elm/Pages/Org_/Repo_.elm b/src/elm/Pages/Org_/Repo_.elm index b56475ed6..e1371d0b2 100644 --- a/src/elm/Pages/Org_/Repo_.elm +++ b/src/elm/Pages/Org_/Repo_.elm @@ -5,12 +5,16 @@ SPDX-License-Identifier: Apache-2.0 module Pages.Org_.Repo_ exposing (Model, Msg, page, view) +import Api.Pagination import Auth import Components.Builds +import Components.Pager +import Dict import Effect exposing (Effect) import Http import Http.Detailed import Layouts +import LinkHeader exposing (WebLink) import List import Maybe.Extra import Page exposing (Page) @@ -27,7 +31,7 @@ page : Auth.User -> Shared.Model -> Route { org : String, repo : String } -> Pag page user shared route = Page.new { init = init shared route - , update = update + , update = update shared route , subscriptions = subscriptions , view = view shared route } @@ -53,6 +57,8 @@ toLayout user route model = type alias Model = { builds : WebData Vela.Builds + , pager : List WebLink + , showFullTimestamps : Bool , showActionsMenus : List Int } @@ -60,12 +66,17 @@ type alias Model = init : Shared.Model -> Route { org : String, repo : String } -> () -> ( Model, Effect Msg ) init shared route () = ( { builds = RemoteData.Loading + , pager = [] + , showFullTimestamps = False , showActionsMenus = [] } , Effect.getRepoBuilds { baseUrl = shared.velaAPI , session = shared.session , onResponse = GetRepoBuildsResponse + , pageNumber = Dict.get "page" route.query |> Maybe.andThen String.toInt + , perPage = Dict.get "perPage" route.query |> Maybe.andThen String.toInt + , maybeEvent = Dict.get "event" route.query , org = route.params.org , repo = route.params.repo } @@ -78,19 +89,25 @@ init shared route () = type Msg = GetRepoBuildsResponse (Result (Http.Detailed.Error String) ( Http.Metadata, List Vela.Build )) + | GotoPage Int | ApproveBuild Org Repo BuildNumber | RestartBuild Org Repo BuildNumber | CancelBuild Org Repo BuildNumber | ShowHideActionsMenus (Maybe Int) (Maybe Bool) + | FilterByEvent (Maybe String) + | ShowHideFullTimestamps -update : Msg -> Model -> ( Model, Effect Msg ) -update msg model = +update : Shared.Model -> Route { org : String, repo : String } -> Msg -> Model -> ( Model, Effect Msg ) +update shared route msg model = case msg of GetRepoBuildsResponse response -> case response of - Ok ( _, builds ) -> - ( { model | builds = RemoteData.Success builds } + Ok ( meta, builds ) -> + ( { model + | builds = RemoteData.Success builds + , pager = Api.Pagination.get meta.headers + } , Effect.none ) @@ -99,6 +116,28 @@ update msg model = , Effect.handleHttpError { httpError = error } ) + GotoPage pageNumber -> + ( { model | builds = RemoteData.Loading } + , Effect.batch + [ Effect.pushRoute + { path = route.path + , query = + Dict.update "page" (\_ -> Just <| String.fromInt pageNumber) route.query + , hash = route.hash + } + , Effect.getRepoBuilds + { baseUrl = shared.velaAPI + , session = shared.session + , onResponse = GetRepoBuildsResponse + , pageNumber = Just pageNumber + , perPage = Dict.get "perPage" route.query |> Maybe.andThen String.toInt + , maybeEvent = Dict.get "event" route.query + , org = route.params.org + , repo = route.params.repo + } + ] + ) + ApproveBuild _ _ _ -> ( model, Effect.none ) @@ -138,6 +177,34 @@ update msg model = , Effect.none ) + FilterByEvent maybeEvent -> + ( { model + | builds = RemoteData.Loading + , pager = [] + } + , Effect.batch + [ Effect.pushRoute + { path = route.path + , query = + Dict.update "event" (\_ -> maybeEvent) route.query + , hash = route.hash + } + , Effect.getRepoBuilds + { baseUrl = shared.velaAPI + , session = shared.session + , onResponse = GetRepoBuildsResponse + , pageNumber = Dict.get "page" route.query |> Maybe.andThen String.toInt + , perPage = Dict.get "perPage" route.query |> Maybe.andThen String.toInt + , maybeEvent = maybeEvent + , org = route.params.org + , repo = route.params.repo + } + ] + ) + + ShowHideFullTimestamps -> + ( { model | showFullTimestamps = not model.showFullTimestamps }, Effect.none ) + -- SUBSCRIPTIONS @@ -161,18 +228,23 @@ view shared route model = , cancelBuild = CancelBuild , showHideActionsMenus = ShowHideActionsMenus } - - body = - Components.Builds.view shared - { msgs = msgs - , builds = model.builds - , showActionsMenus = model.showActionsMenus - , maybeEvent = Nothing - , showFullTimestamps = True - } in { title = route.params.org ++ "/" ++ route.params.repo , body = - [ body + [ Components.Builds.viewHeader + { maybeEvent = Dict.get "event" route.query + , showFullTimestamps = model.showFullTimestamps + , filterByEvent = FilterByEvent + , showHideFullTimestamps = ShowHideFullTimestamps + } + , Components.Pager.view model.pager Components.Pager.defaultLabels GotoPage + , Components.Builds.view shared + { msgs = msgs + , builds = model.builds + , showActionsMenus = model.showActionsMenus + , maybeEvent = Dict.get "event" route.query + , showFullTimestamps = model.showFullTimestamps + } + , Components.Pager.view model.pager Components.Pager.defaultLabels GotoPage ] } diff --git a/src/elm/Pages/Org_/Repo_/Deployments_.elm b/src/elm/Pages/Org_/Repo_/Deployments_.elm index beb8eac07..af32d3bf7 100644 --- a/src/elm/Pages/Org_/Repo_/Deployments_.elm +++ b/src/elm/Pages/Org_/Repo_/Deployments_.elm @@ -10,6 +10,7 @@ import Auth import Components.Pager import Components.Svgs as SvgBuilder import Components.Table as Table +import Dict import Effect exposing (Effect) import FeatherIcons import Html @@ -33,16 +34,17 @@ import Html.Attributes import Http import Http.Detailed import Layouts +import LinkHeader exposing (WebLink) import List import Page exposing (Page) import RemoteData exposing (RemoteData(..), WebData) import Route exposing (Route) -import Routes +import Route.Path import Shared import Svg.Attributes import Utils.Errors as Errors import Utils.Helpers as Util -import Vela exposing (Deployment, Org, Repo, Repository) +import Vela import View exposing (View) @@ -50,7 +52,7 @@ page : Auth.User -> Shared.Model -> Route { org : String, repo : String } -> Pag page user shared route = Page.new { init = init shared route - , update = update + , update = update shared route , subscriptions = subscriptions , view = view shared route } @@ -76,17 +78,21 @@ toLayout user route model = type alias Model = { deployments : WebData (List Vela.Deployment) + , pager : List WebLink } init : Shared.Model -> Route { org : String, repo : String } -> () -> ( Model, Effect Msg ) init shared route () = ( { deployments = RemoteData.Loading + , pager = [] } , Effect.getRepoDeployments { baseUrl = shared.velaAPI , session = shared.session , onResponse = GetRepoDeploymentsResponse + , pageNumber = Dict.get "page" route.query |> Maybe.andThen String.toInt + , perPage = Dict.get "perPage" route.query |> Maybe.andThen String.toInt , org = route.params.org , repo = route.params.repo } @@ -99,15 +105,19 @@ init shared route () = type Msg = GetRepoDeploymentsResponse (Result (Http.Detailed.Error String) ( Http.Metadata, List Vela.Deployment )) + | GotoPage Int -update : Msg -> Model -> ( Model, Effect Msg ) -update msg model = +update : Shared.Model -> Route { org : String, repo : String } -> Msg -> Model -> ( Model, Effect Msg ) +update shared route msg model = case msg of GetRepoDeploymentsResponse response -> case response of - Ok ( _, deployments ) -> - ( { model | deployments = RemoteData.Success deployments } + Ok ( meta, deployments ) -> + ( { model + | deployments = RemoteData.Success deployments + , pager = Api.Pagination.get meta.headers + } , Effect.none ) @@ -116,6 +126,27 @@ update msg model = , Effect.handleHttpError { httpError = error } ) + GotoPage pageNumber -> + ( { model | deployments = RemoteData.Loading } + , Effect.batch + [ Effect.replaceRoute + { path = route.path + , query = + Dict.update "page" (\_ -> Just <| String.fromInt pageNumber) route.query + , hash = route.hash + } + , Effect.getRepoDeployments + { baseUrl = shared.velaAPI + , session = shared.session + , onResponse = GetRepoDeploymentsResponse + , pageNumber = Just pageNumber + , perPage = Dict.get "perPage" route.query |> Maybe.andThen String.toInt + , org = route.params.org + , repo = route.params.repo + } + ] + ) + -- SUBSCRIPTIONS @@ -132,26 +163,18 @@ subscriptions model = view : Shared.Model -> Route { org : String, repo : String } -> Model -> View Msg view shared route model = - let - cloneUrlChangeMe = - "" - - table = - viewDeployments route.params.org route.params.repo cloneUrlChangeMe model.deployments - in { title = "Pages.Org_.Repo_.Deployments_" , body = - [ table - - -- , Pager.view shared.repo.deployments.pager Pager.defaultLabels GotoPage + [ viewDeployments route.params.org route.params.repo model.deployments + , Components.Pager.view model.pager Components.Pager.defaultLabels GotoPage ] } {-| viewDeployments : renders a list of deployments -} -viewDeployments : String -> String -> String -> WebData (List Vela.Deployment) -> Html Msg -viewDeployments org repo clone deployments = +viewDeployments : String -> String -> WebData (List Vela.Deployment) -> Html Msg +viewDeployments org repo deployments = let addButton = a @@ -159,8 +182,10 @@ viewDeployments org repo clone deployments = , class "-outline" , class "button-with-icon" , Util.testAttribute "add-deployment" - , Routes.href <| - Routes.AddDeploymentRoute org repo + + -- todo: need add deployment path to do this + -- , Route.Path.href <| + -- Route.Path.Org_Repo_Deployments_ { org = org, repo = repo } ] [ text "Add Deployment" , FeatherIcons.plus @@ -178,7 +203,7 @@ viewDeployments org repo clone deployments = case deployments of RemoteData.Success d -> ( text "No deployments found for this repo" - , deploymentsToRows org repo clone d + , deploymentsToRows org repo d ) RemoteData.Failure error -> @@ -222,9 +247,9 @@ viewDeployments org repo clone deployments = {-| deploymentsToRows : takes list of deployments and produces list of Table rows -} -deploymentsToRows : String -> String -> String -> List Deployment -> Table.Rows Deployment Msg -deploymentsToRows org repo clone deployments = - List.map (\deployment -> Table.Row deployment (renderDeployment org repo clone)) deployments +deploymentsToRows : String -> String -> List Vela.Deployment -> Table.Rows Vela.Deployment Msg +deploymentsToRows org repo deployments = + List.map (\deployment -> Table.Row deployment (renderDeployment org repo)) deployments {-| tableHeaders : returns table headers for deployments table @@ -244,8 +269,14 @@ tableHeaders = {-| renderDeployment : takes deployment and renders a table row -} -renderDeployment : String -> String -> String -> Deployment -> Html Msg -renderDeployment org repo clone deployment = +renderDeployment : String -> String -> Vela.Deployment -> Html Msg +renderDeployment org repo deployment = + let + -- todo: somehow build the repo clone link and append the commit hash + -- Util.buildRepoCloneLink org repo + repoCloneLink = + "" + in tr [ Util.testAttribute <| "deployments-row" ] [ td [ attribute "data-label" "" @@ -274,7 +305,7 @@ renderDeployment org repo clone deployment = , class "break-word" , Util.testAttribute <| "deployments-row-commit" ] - [ a [ href <| Util.buildRefURL clone deployment.commit ] + [ a [ href <| Util.buildRefURL repoCloneLink deployment.commit ] [ text <| Util.trimCommitHash deployment.commit ] ] , td @@ -309,12 +340,16 @@ renderDeployment org repo clone deployment = {-| redeployLink : takes org, repo and deployment and renders a link to redirect to the promote deployment page -} -redeployLink : Org -> Repo -> Deployment -> Html Msg +redeployLink : String -> String -> Vela.Deployment -> Html Msg redeployLink org repo deployment = a [ class "redeploy-link" , attribute "aria-label" <| "redeploy deployment " ++ String.fromInt deployment.id - , Routes.href <| Routes.PromoteDeployment org repo (String.fromInt deployment.id) + + -- todo: need add deployment path to do this + -- , Routes.href <| Routes.PromoteDeployment org repo (String.fromInt deployment.id) + -- , Route.Path.href <| + -- Route.Path.Org_Repo_Deployments_ { org = org, repo = repo } , Util.testAttribute "redeploy-deployment" ] [ text "Redeploy" diff --git a/src/elm/Shared.elm b/src/elm/Shared.elm index b6fe81a4b..adaa0f1a9 100644 --- a/src/elm/Shared.elm +++ b/src/elm/Shared.elm @@ -267,6 +267,14 @@ update route msg model = _ -> ( model, Effect.none ) + -- THEME + Shared.Msg.SetTheme options -> + if options.theme == model.theme then + ( model, Effect.none ) + + else + ( { model | theme = options.theme }, Effect.sendCmd <| Interop.setTheme <| Vela.encodeTheme options.theme ) + -- ALERTS Shared.Msg.AlertsUpdate subMsg -> Alerting.update Alerts.successConfig Shared.Msg.AlertsUpdate subMsg model @@ -309,8 +317,8 @@ update route msg model = ) -- DOM - Shared.Msg.FocusOn target -> - ( model, Browser.Dom.focus target |> Task.attempt Shared.Msg.FocusResult |> Effect.sendCmd ) + Shared.Msg.FocusOn options -> + ( model, Browser.Dom.focus options.target |> Task.attempt Shared.Msg.FocusResult |> Effect.sendCmd ) Shared.Msg.FocusResult result -> -- handle success or failure here @@ -323,14 +331,6 @@ update route msg model = -- successfully focus the dom ( model, Effect.none ) - -- THEME - Shared.Msg.SetTheme theme -> - if theme == model.theme then - ( model, Effect.none ) - - else - ( { model | theme = theme }, Effect.sendCmd <| Interop.setTheme <| Vela.encodeTheme theme ) - subscriptions : Route () -> Model -> Sub Msg subscriptions _ model = diff --git a/src/elm/Shared/Msg.elm b/src/elm/Shared/Msg.elm index 2b02288fa..9cf62ccd8 100644 --- a/src/elm/Shared/Msg.elm +++ b/src/elm/Shared/Msg.elm @@ -27,6 +27,8 @@ type Msg | RepoFavoriteResponse { favorite : String, favorited : Bool } (Result (Http.Detailed.Error String) ( Http.Metadata, CurrentUser )) -- PAGINATION | GotoPage { pageNumber : Int } + -- THEME + | SetTheme { theme : Vela.Theme } -- ALERTS | AddAlertError { content : String, addToastIfUnique : Bool } | AddAlertSuccess { content : String, addToastIfUnique : Bool } @@ -34,7 +36,5 @@ type Msg -- ERRORS | HandleHttpError (Http.Detailed.Error String) -- DOM - | FocusOn String + | FocusOn { target : String } | FocusResult (Result Browser.Dom.Error ()) - -- THEME - | SetTheme Vela.Theme