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

     1  module Build.Shortcuts exposing (handleDelivery, keyboardHelp)
     2  
     3  import Build.Header.Models exposing (HistoryItem)
     4  import Build.Models exposing (ShortcutsModel)
     5  import Concourse.BuildStatus
     6  import EffectTransformer exposing (ET)
     7  import Html exposing (Html)
     8  import Html.Attributes exposing (class, classList)
     9  import Keyboard
    10  import Maybe.Extra
    11  import Message.Effects exposing (Effect(..))
    12  import Message.Message exposing (DomID(..), Message(..))
    13  import Message.ScrollDirection exposing (ScrollDirection(..))
    14  import Message.Subscription exposing (Delivery(..))
    15  import Routes
    16  
    17  
    18  bodyId : String
    19  bodyId =
    20      "build-body"
    21  
    22  
    23  keyboardHelp : Bool -> Html Message
    24  keyboardHelp showHelp =
    25      let
    26          shortcuts =
    27              [ { keys = [ "h", "l" ], description = "previous/next build" }
    28              , { keys = [ "j", "k" ], description = "scroll down/up" }
    29              , { keys = [ "T" ], description = "trigger a new build" }
    30              , { keys = [ "R" ], description = "rerun the current build" }
    31              , { keys = [ "A" ], description = "abort build" }
    32              , { keys = [ "gg" ], description = "scroll to the top" }
    33              , { keys = [ "G" ], description = "scroll to the bottom" }
    34              , { keys = [ "?" ], description = "hide/show help" }
    35              ]
    36  
    37          keySpan key =
    38              Html.span [ class "key" ] [ Html.text key ]
    39  
    40          helpLine shortcut =
    41              Html.div
    42                  [ class "help-line" ]
    43                  [ Html.div [ class "keys" ] (List.map keySpan shortcut.keys)
    44                  , Html.text shortcut.description
    45                  ]
    46      in
    47      Html.div
    48          [ classList
    49              [ ( "keyboard-help", True )
    50              , ( "hidden", not showHelp )
    51              ]
    52          ]
    53          (Html.div [ class "help-title" ] [ Html.text "keyboard shortcuts" ]
    54              :: List.map helpLine shortcuts
    55          )
    56  
    57  
    58  historyItem : ShortcutsModel r -> HistoryItem
    59  historyItem model =
    60      { id = model.id
    61      , name = model.name
    62      , status = model.status
    63      , duration = model.duration
    64      }
    65  
    66  
    67  prevHistoryItem : List HistoryItem -> HistoryItem -> Maybe HistoryItem
    68  prevHistoryItem builds b =
    69      case builds of
    70          first :: second :: rest ->
    71              if first == b then
    72                  Just second
    73  
    74              else
    75                  prevHistoryItem (second :: rest) b
    76  
    77          _ ->
    78              Nothing
    79  
    80  
    81  nextHistoryItem : List HistoryItem -> HistoryItem -> Maybe HistoryItem
    82  nextHistoryItem builds b =
    83      case builds of
    84          first :: second :: rest ->
    85              if second == b then
    86                  Just first
    87  
    88              else
    89                  nextHistoryItem (second :: rest) b
    90  
    91          _ ->
    92              Nothing
    93  
    94  
    95  handleDelivery : Delivery -> ET (ShortcutsModel r)
    96  handleDelivery delivery ( model, effects ) =
    97      case delivery of
    98          KeyDown keyEvent ->
    99              handleKeyPressed keyEvent ( model, effects )
   100  
   101          KeyUp keyEvent ->
   102              case keyEvent.code of
   103                  Keyboard.T ->
   104                      ( { model | isTriggerBuildKeyDown = False }, effects )
   105  
   106                  _ ->
   107                      ( model, effects )
   108  
   109          _ ->
   110              ( model, effects )
   111  
   112  
   113  handleKeyPressed : Keyboard.KeyEvent -> ET (ShortcutsModel r)
   114  handleKeyPressed keyEvent ( model, effects ) =
   115      let
   116          newModel =
   117              case ( model.previousKeyPress, keyEvent.shiftKey, keyEvent.code ) of
   118                  ( Nothing, False, Keyboard.G ) ->
   119                      { model | previousKeyPress = Just keyEvent }
   120  
   121                  _ ->
   122                      { model | previousKeyPress = Nothing }
   123      in
   124      if Keyboard.hasControlModifier keyEvent then
   125          ( newModel, effects )
   126  
   127      else
   128          case ( keyEvent.code, keyEvent.shiftKey ) of
   129              ( Keyboard.J, False ) ->
   130                  ( newModel, [ Scroll Down bodyId ] )
   131  
   132              ( Keyboard.K, False ) ->
   133                  ( newModel, [ Scroll Up bodyId ] )
   134  
   135              ( Keyboard.G, True ) ->
   136                  ( { newModel | autoScroll = True }, [ Scroll ToBottom bodyId ] )
   137  
   138              ( Keyboard.G, False ) ->
   139                  if
   140                      (model.previousKeyPress |> Maybe.map .code)
   141                          == Just Keyboard.G
   142                  then
   143                      ( { newModel | autoScroll = False }, [ Scroll ToTop bodyId ] )
   144  
   145                  else
   146                      ( newModel, effects )
   147  
   148              ( Keyboard.Slash, True ) ->
   149                  ( { newModel | showHelp = not newModel.showHelp }, effects )
   150  
   151              ( Keyboard.H, False ) ->
   152                  case nextHistoryItem model.history (historyItem model) of
   153                      Just item ->
   154                          ( newModel
   155                          , effects
   156                              ++ [ NavigateTo <|
   157                                      Routes.toString <|
   158                                          Routes.buildRoute
   159                                              item.id
   160                                              item.name
   161                                              newModel.job
   162                                 ]
   163                          )
   164  
   165                      Nothing ->
   166                          ( newModel, effects )
   167  
   168              ( Keyboard.L, False ) ->
   169                  case prevHistoryItem newModel.history (historyItem newModel) of
   170                      Just item ->
   171                          ( newModel
   172                          , effects
   173                              ++ [ NavigateTo <|
   174                                      Routes.toString <|
   175                                          Routes.buildRoute
   176                                              item.id
   177                                              item.name
   178                                              newModel.job
   179                                 ]
   180                          )
   181  
   182                      Nothing ->
   183                          ( newModel, effects )
   184  
   185              ( Keyboard.T, True ) ->
   186                  if not newModel.isTriggerBuildKeyDown then
   187                      (newModel.job
   188                          |> Maybe.map (DoTriggerBuild >> (::) >> Tuple.mapSecond)
   189                          |> Maybe.withDefault identity
   190                      )
   191                          ( { newModel | isTriggerBuildKeyDown = True }, effects )
   192  
   193                  else
   194                      ( newModel, effects )
   195  
   196              ( Keyboard.R, True ) ->
   197                  ( newModel
   198                  , effects
   199                      ++ (if Concourse.BuildStatus.isRunning newModel.status then
   200                              []
   201  
   202                          else
   203                              newModel.job
   204                                  |> Maybe.map
   205                                      (\j ->
   206                                          RerunJobBuild
   207                                              { teamName = j.teamName
   208                                              , pipelineName = j.pipelineName
   209                                              , jobName = j.jobName
   210                                              , buildName = newModel.name
   211                                              }
   212                                      )
   213                                  |> Maybe.Extra.toList
   214                         )
   215                  )
   216  
   217              ( Keyboard.A, True ) ->
   218                  if Just (historyItem newModel) == List.head newModel.history then
   219                      ( newModel, DoAbortBuild newModel.id :: effects )
   220  
   221                  else
   222                      ( newModel, effects )
   223  
   224              _ ->
   225                  ( newModel, effects )