github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/web/elm/src/Build/Header/Views.elm (about)

     1  module Build.Header.Views exposing
     2      ( BackgroundShade(..)
     3      , BuildDuration(..)
     4      , BuildTab
     5      , ButtonType(..)
     6      , Header
     7      , Timespan(..)
     8      , Timestamp(..)
     9      , Widget(..)
    10      , viewHeader
    11      )
    12  
    13  import Assets
    14  import Build.Styles as Styles
    15  import Colors
    16  import Concourse
    17  import Concourse.BuildStatus exposing (BuildStatus)
    18  import Html exposing (Html)
    19  import Html.Attributes
    20      exposing
    21          ( attribute
    22          , class
    23          , href
    24          , id
    25          , style
    26          , title
    27          )
    28  import Html.Events exposing (onBlur, onFocus, onMouseEnter, onMouseLeave)
    29  import Html.Lazy
    30  import Message.Message as Message exposing (Message(..))
    31  import Routes
    32  import StrictEvents exposing (onLeftClick, onWheel)
    33  import Views.Icon as Icon
    34  
    35  
    36  historyId : String
    37  historyId =
    38      "builds"
    39  
    40  
    41  type alias Header =
    42      { leftWidgets : List Widget
    43      , rightWidgets : List Widget
    44      , backgroundColor : BuildStatus
    45      , tabs : List BuildTab
    46      }
    47  
    48  
    49  type Widget
    50      = Button (Maybe ButtonView)
    51      | Title String (Maybe Concourse.JobIdentifier)
    52      | Duration BuildDuration
    53  
    54  
    55  type BuildDuration
    56      = Pending
    57      | Running Timestamp
    58      | Cancelled Timestamp
    59      | Finished
    60          { started : Timestamp
    61          , finished : Timestamp
    62          , duration : Timespan
    63          }
    64  
    65  
    66  type Timestamp
    67      = Absolute String (Maybe Timespan)
    68      | Relative Timespan String
    69  
    70  
    71  type Timespan
    72      = JustSeconds Int
    73      | MinutesAndSeconds Int Int
    74      | HoursAndMinutes Int Int
    75      | DaysAndHours Int Int
    76  
    77  
    78  type alias BuildTab =
    79      { id : Int
    80      , name : String
    81      , background : BuildStatus
    82      , href : Routes.Route
    83      , isCurrent : Bool
    84      }
    85  
    86  
    87  type alias ButtonView =
    88      { type_ : ButtonType
    89      , isClickable : Bool
    90      , backgroundShade : BackgroundShade
    91      , backgroundColor : BuildStatus
    92      , tooltip : Bool
    93      }
    94  
    95  
    96  type BackgroundShade
    97      = Light
    98      | Dark
    99  
   100  
   101  type ButtonType
   102      = Abort
   103      | Trigger
   104      | Rerun
   105  
   106  
   107  viewHeader : Header -> Html Message
   108  viewHeader header =
   109      Html.div [ class "fixed-header" ]
   110          [ Html.div
   111              ([ id "build-header"
   112               , class "build-header"
   113               ]
   114                  ++ Styles.header header.backgroundColor
   115              )
   116              [ Html.div [] (List.map viewWidget header.leftWidgets)
   117              , Html.div [ style "display" "flex" ] (List.map viewWidget header.rightWidgets)
   118              ]
   119          , viewHistory header.backgroundColor header.tabs
   120          ]
   121  
   122  
   123  viewWidget : Widget -> Html Message
   124  viewWidget widget =
   125      case widget of
   126          Button button ->
   127              Maybe.map viewButton button |> Maybe.withDefault (Html.text "")
   128  
   129          Title name jobId ->
   130              Html.h1 [] [ viewTitle name jobId ]
   131  
   132          Duration duration ->
   133              viewDuration duration
   134  
   135  
   136  viewDuration : BuildDuration -> Html Message
   137  viewDuration buildDuration =
   138      Html.table [ class "dictionary build-duration" ] <|
   139          case buildDuration of
   140              Pending ->
   141                  [ Html.tr []
   142                      [ Html.td [ class "dict-key" ] [ Html.text "pending" ]
   143                      , Html.td [ class "dict-value" ] []
   144                      ]
   145                  ]
   146  
   147              Running timestamp ->
   148                  [ Html.tr []
   149                      [ Html.td [ class "dict-key" ] [ Html.text "started" ]
   150                      , viewTimestamp timestamp
   151                      ]
   152                  ]
   153  
   154              Cancelled timestamp ->
   155                  [ Html.tr []
   156                      [ Html.td [ class "dict-key" ] [ Html.text "finished" ]
   157                      , viewTimestamp timestamp
   158                      ]
   159                  ]
   160  
   161              Finished { started, finished, duration } ->
   162                  [ Html.tr []
   163                      [ Html.td [ class "dict-key" ] [ Html.text "started" ]
   164                      , viewTimestamp started
   165                      ]
   166                  , Html.tr []
   167                      [ Html.td [ class "dict-key" ] [ Html.text "finished" ]
   168                      , viewTimestamp finished
   169                      ]
   170                  , Html.tr []
   171                      [ Html.td [ class "dict-key" ] [ Html.text "duration" ]
   172                      , Html.td [ class "dict-value" ] [ Html.text <| viewTimespan duration ]
   173                      ]
   174                  ]
   175  
   176  
   177  viewTimestamp : Timestamp -> Html Message
   178  viewTimestamp timestamp =
   179      case timestamp of
   180          Relative timespan formatted ->
   181              Html.td
   182                  [ class "dict-value"
   183                  , title formatted
   184                  ]
   185                  [ Html.span [] [ Html.text <| viewTimespan timespan ++ " ago" ] ]
   186  
   187          Absolute formatted (Just timespan) ->
   188              Html.td
   189                  [ class "dict-value"
   190                  , title <| viewTimespan timespan
   191                  ]
   192                  [ Html.span [] [ Html.text formatted ] ]
   193  
   194          Absolute formatted Nothing ->
   195              Html.td
   196                  [ class "dict-value"
   197                  ]
   198                  [ Html.span [] [ Html.text formatted ] ]
   199  
   200  
   201  viewTimespan : Timespan -> String
   202  viewTimespan timespan =
   203      case timespan of
   204          JustSeconds s ->
   205              String.fromInt s ++ "s"
   206  
   207          MinutesAndSeconds m s ->
   208              String.fromInt m ++ "m " ++ String.fromInt s ++ "s"
   209  
   210          HoursAndMinutes h m ->
   211              String.fromInt h ++ "h " ++ String.fromInt m ++ "m"
   212  
   213          DaysAndHours d h ->
   214              String.fromInt d ++ "d " ++ String.fromInt h ++ "h"
   215  
   216  
   217  lazyViewHistory : BuildStatus -> List BuildTab -> Html Message
   218  lazyViewHistory backgroundColor =
   219      Html.Lazy.lazy (viewBuildTabs backgroundColor)
   220  
   221  
   222  viewBuildTabs : BuildStatus -> List BuildTab -> Html Message
   223  viewBuildTabs backgroundColor =
   224      List.map (viewBuildTab backgroundColor) >> Html.ul [ id historyId ]
   225  
   226  
   227  viewBuildTab : BuildStatus -> BuildTab -> Html Message
   228  viewBuildTab backgroundColor tab =
   229      Html.li
   230          ((id <| String.fromInt tab.id)
   231              :: Styles.historyItem backgroundColor tab.isCurrent tab.background
   232          )
   233          [ Html.a
   234              [ onLeftClick <| Click <| Message.BuildTab tab.id tab.name
   235              , href <| Routes.toString tab.href
   236              ]
   237              [ Html.text tab.name ]
   238          ]
   239  
   240  
   241  viewButton : ButtonView -> Html Message
   242  viewButton { type_, tooltip, backgroundColor, backgroundShade, isClickable } =
   243      let
   244          image =
   245              case type_ of
   246                  Abort ->
   247                      Assets.AbortCircleIcon |> Assets.CircleOutlineIcon
   248  
   249                  Trigger ->
   250                      Assets.AddCircleIcon |> Assets.CircleOutlineIcon
   251  
   252                  Rerun ->
   253                      Assets.RerunIcon
   254  
   255          accessibilityLabel =
   256              case type_ of
   257                  Abort ->
   258                      "Abort Build"
   259  
   260                  Trigger ->
   261                      "Trigger Build"
   262  
   263                  Rerun ->
   264                      "Rerun Build"
   265  
   266          domID =
   267              case type_ of
   268                  Abort ->
   269                      Message.AbortBuildButton
   270  
   271                  Trigger ->
   272                      Message.TriggerBuildButton
   273  
   274                  Rerun ->
   275                      Message.RerunBuildButton
   276  
   277          styles =
   278              [ style "padding" "10px"
   279              , style "outline" "none"
   280              , style "margin" "0"
   281              , style "border-width" "0 0 0 1px"
   282              , style "border-color" <| Colors.buildStatusColor False backgroundColor
   283              , style "border-style" "solid"
   284              , style "position" "relative"
   285              , style "background-color" <|
   286                  Colors.buildStatusColor
   287                      (backgroundShade == Light)
   288                      backgroundColor
   289              , style "cursor" <|
   290                  if isClickable then
   291                      "pointer"
   292  
   293                  else
   294                      "default"
   295              ]
   296      in
   297      Html.button
   298          ([ attribute "role" "button"
   299           , attribute "tabindex" "0"
   300           , attribute "aria-label" accessibilityLabel
   301           , attribute "title" accessibilityLabel
   302           , onLeftClick <| Click domID
   303           , onMouseEnter <| Hover <| Just domID
   304           , onMouseLeave <| Hover Nothing
   305           , onFocus <| Hover <| Just domID
   306           , onBlur <| Hover Nothing
   307           ]
   308              ++ styles
   309          )
   310          [ Icon.icon
   311              { sizePx = 40
   312              , image = image
   313              }
   314              []
   315          , tooltipArrow tooltip type_
   316          , viewTooltip tooltip type_
   317          ]
   318  
   319  
   320  tooltipArrow : Bool -> ButtonType -> Html Message
   321  tooltipArrow tooltip type_ =
   322      case ( tooltip, type_ ) of
   323          ( True, Trigger ) ->
   324              Html.div
   325                  Styles.buttonTooltipArrow
   326                  []
   327  
   328          ( True, Rerun ) ->
   329              Html.div
   330                  Styles.buttonTooltipArrow
   331                  []
   332  
   333          _ ->
   334              Html.text ""
   335  
   336  
   337  viewTooltip : Bool -> ButtonType -> Html Message
   338  viewTooltip tooltip type_ =
   339      case ( tooltip, type_ ) of
   340          ( True, Trigger ) ->
   341              Html.div
   342                  (Styles.buttonTooltip 240)
   343                  [ Html.text <|
   344                      "manual triggering disabled in job config"
   345                  ]
   346  
   347          ( True, Rerun ) ->
   348              Html.div
   349                  (Styles.buttonTooltip 165)
   350                  [ Html.text <|
   351                      "re-run with the same inputs"
   352                  ]
   353  
   354          _ ->
   355              Html.text ""
   356  
   357  
   358  viewTitle : String -> Maybe Concourse.JobIdentifier -> Html Message
   359  viewTitle name jobID =
   360      case jobID of
   361          Just id ->
   362              Html.a
   363                  [ href <|
   364                      Routes.toString <|
   365                          Routes.Job { id = id, page = Nothing }
   366                  ]
   367                  [ Html.span [ class "build-name" ] [ Html.text id.jobName ]
   368                  , Html.span [ style "letter-spacing" "-1px" ] [ Html.text (" #" ++ name) ]
   369                  ]
   370  
   371          _ ->
   372              Html.text name
   373  
   374  
   375  viewHistory : BuildStatus -> List BuildTab -> Html Message
   376  viewHistory backgroundColor =
   377      lazyViewHistory backgroundColor
   378          >> List.singleton
   379          >> Html.div [ onWheel ScrollBuilds ]