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 ]