github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/web/elm/src/Dashboard/Footer.elm (about) 1 module Dashboard.Footer exposing (handleDelivery, view) 2 3 import Assets 4 import Concourse.Cli as Cli 5 import Concourse.PipelineStatus as PipelineStatus exposing (PipelineStatus(..)) 6 import Dashboard.Group.Models exposing (Pipeline) 7 import Dashboard.Models exposing (Dropdown(..), FooterModel) 8 import Dashboard.Styles as Styles 9 import Dict exposing (Dict) 10 import HoverState 11 import Html exposing (Html) 12 import Html.Attributes exposing (attribute, class, download, href, id, style) 13 import Html.Events exposing (onMouseEnter, onMouseLeave) 14 import Keyboard 15 import Message.Effects as Effects 16 import Message.Message exposing (DomID(..), Message(..)) 17 import Message.Subscription exposing (Delivery(..), Interval(..)) 18 import Routes 19 import ScreenSize 20 import Views.Icon as Icon 21 import Views.Toggle as Toggle 22 23 24 handleDelivery : 25 Delivery 26 -> ( FooterModel r, List Effects.Effect ) 27 -> ( FooterModel r, List Effects.Effect ) 28 handleDelivery delivery ( model, effects ) = 29 case delivery of 30 KeyDown keyEvent -> 31 case keyEvent.code of 32 -- '/' key 33 Keyboard.Slash -> 34 if keyEvent.shiftKey && model.dropdown == Hidden then 35 ( { model 36 | showHelp = 37 if 38 model.pipelines 39 |> Maybe.withDefault Dict.empty 40 |> Dict.values 41 |> List.all List.isEmpty 42 then 43 False 44 45 else 46 not model.showHelp 47 } 48 , effects 49 ) 50 51 else 52 ( model, effects ) 53 54 _ -> 55 ( { model | hideFooter = False, hideFooterCounter = 0 } 56 , effects 57 ) 58 59 Moused _ -> 60 ( { model | hideFooter = False, hideFooterCounter = 0 }, effects ) 61 62 ClockTicked OneSecond _ -> 63 ( if model.hideFooterCounter > 4 then 64 { model | hideFooter = True } 65 66 else 67 { model | hideFooterCounter = model.hideFooterCounter + 1 } 68 , effects 69 ) 70 71 _ -> 72 ( model, effects ) 73 74 75 view : 76 { a 77 | hovered : HoverState.HoverState 78 , screenSize : ScreenSize.ScreenSize 79 , version : String 80 } 81 -> FooterModel r 82 -> Html Message 83 view session model = 84 if model.showHelp then 85 keyboardHelp 86 87 else if not model.hideFooter then 88 infoBar session model 89 90 else 91 Html.text "" 92 93 94 keyboardHelp : Html Message 95 keyboardHelp = 96 Html.div 97 [ class "keyboard-help", id "keyboard-help" ] 98 [ Html.div 99 [ class "help-title" ] 100 [ Html.text "keyboard shortcuts" ] 101 , Html.div 102 [ class "help-line" ] 103 [ Html.div 104 [ class "keys" ] 105 [ Html.span 106 [ class "key" ] 107 [ Html.text "/" ] 108 ] 109 , Html.text "search" 110 ] 111 , Html.div 112 [ class "help-line" ] 113 [ Html.div 114 [ class "keys" ] 115 [ Html.span 116 [ class "key" ] 117 [ Html.text "?" ] 118 ] 119 , Html.text "hide/show help" 120 ] 121 ] 122 123 124 infoBar : 125 { a 126 | hovered : HoverState.HoverState 127 , screenSize : ScreenSize.ScreenSize 128 , version : String 129 } 130 -> 131 { b 132 | highDensity : Bool 133 , dashboardView : Routes.DashboardView 134 , pipelines : Maybe (Dict String (List Pipeline)) 135 } 136 -> Html Message 137 infoBar session model = 138 Html.div 139 (id "dashboard-info" 140 :: Styles.infoBar 141 { hideLegend = hideLegend model 142 , screenSize = session.screenSize 143 } 144 ) 145 [ legend session model 146 , concourseInfo session 147 ] 148 149 150 legend : 151 { a | screenSize : ScreenSize.ScreenSize } 152 -> 153 { b 154 | pipelines : Maybe (Dict String (List Pipeline)) 155 , highDensity : Bool 156 , dashboardView : Routes.DashboardView 157 } 158 -> Html Message 159 legend session model = 160 if hideLegend model then 161 Html.text "" 162 163 else 164 Html.div 165 (id "legend" :: Styles.legend) 166 <| 167 List.map legendItem 168 [ PipelineStatusPending False 169 , PipelineStatusPaused 170 ] 171 ++ Html.div 172 Styles.legendItem 173 [ Icon.icon 174 { sizePx = 20 175 , image = Assets.RunningLegend 176 } 177 [] 178 , Html.div [ style "width" "10px" ] [] 179 , Html.text "running" 180 ] 181 :: List.map legendItem 182 [ PipelineStatusFailed PipelineStatus.Running 183 , PipelineStatusErrored PipelineStatus.Running 184 , PipelineStatusAborted PipelineStatus.Running 185 , PipelineStatusSucceeded PipelineStatus.Running 186 ] 187 ++ legendSeparator session.screenSize 188 ++ [ toggleView model ] 189 190 191 concourseInfo : 192 { a | hovered : HoverState.HoverState, version : String } 193 -> Html Message 194 concourseInfo { hovered, version } = 195 Html.div (id "concourse-info" :: Styles.info) 196 [ Html.div 197 Styles.infoItem 198 [ Html.text <| "version: v" ++ version ] 199 , Html.div Styles.infoItem <| 200 [ Html.span 201 [ style "margin-right" "10px" ] 202 [ Html.text "cli: " ] 203 ] 204 ++ List.map (cliIcon hovered) Cli.clis 205 ] 206 207 208 hideLegend : { a | pipelines : Maybe (Dict String (List Pipeline)) } -> Bool 209 hideLegend { pipelines } = 210 pipelines 211 |> Maybe.withDefault Dict.empty 212 |> Dict.values 213 |> List.all List.isEmpty 214 215 216 legendItem : PipelineStatus -> Html Message 217 legendItem status = 218 Html.div 219 Styles.legendItem 220 [ Icon.icon 221 { sizePx = 20, image = Assets.PipelineStatusIcon status } 222 Styles.pipelineStatusIcon 223 , Html.div [ style "width" "10px" ] [] 224 , Html.text <| PipelineStatus.show status 225 ] 226 227 228 toggleView : 229 { r 230 | highDensity : Bool 231 , dashboardView : Routes.DashboardView 232 } 233 -> Html Message 234 toggleView { highDensity, dashboardView } = 235 Toggle.toggleSwitch 236 { ariaLabel = "Toggle high-density view" 237 , hrefRoute = 238 Routes.Dashboard 239 { searchType = 240 if highDensity then 241 Routes.Normal "" 242 243 else 244 Routes.HighDensity 245 , dashboardView = dashboardView 246 } 247 , text = "high-density" 248 , textDirection = Toggle.Right 249 , on = highDensity 250 , styles = Styles.highDensityToggle 251 } 252 253 254 legendSeparator : ScreenSize.ScreenSize -> List (Html Message) 255 legendSeparator screenSize = 256 case screenSize of 257 ScreenSize.Mobile -> 258 [] 259 260 ScreenSize.Desktop -> 261 [ Html.div Styles.legendSeparator [ Html.text "|" ] ] 262 263 ScreenSize.BigDesktop -> 264 [ Html.div Styles.legendSeparator [ Html.text "|" ] ] 265 266 267 cliIcon : HoverState.HoverState -> Cli.Cli -> Html Message 268 cliIcon hovered cli = 269 Html.a 270 ([ href <| Cli.downloadUrl cli 271 , attribute "aria-label" <| Cli.label cli 272 , id <| "cli-" ++ Cli.id cli 273 , onMouseEnter <| Hover <| Just <| FooterCliIcon cli 274 , onMouseLeave <| Hover Nothing 275 , download "" 276 ] 277 ++ Styles.infoCliIcon 278 { hovered = HoverState.isHovered (FooterCliIcon cli) hovered 279 , cli = cli 280 } 281 ) 282 []