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

     1  module Routes exposing
     2      ( DashboardView(..)
     3      , Highlight(..)
     4      , Route(..)
     5      , SearchType(..)
     6      , StepID
     7      , Transition
     8      , buildRoute
     9      , extractPid
    10      , extractQuery
    11      , jobRoute
    12      , parsePath
    13      , pipelineRoute
    14      , showHighlight
    15      , toString
    16      , tokenToFlyRoute
    17      )
    18  
    19  import Api.Pagination
    20  import Concourse
    21  import Concourse.Pagination as Pagination exposing (Direction(..))
    22  import Dict
    23  import Maybe.Extra
    24  import Url
    25  import Url.Builder as Builder
    26  import Url.Parser
    27      exposing
    28          ( (</>)
    29          , (<?>)
    30          , Parser
    31          , custom
    32          , fragment
    33          , int
    34          , map
    35          , oneOf
    36          , parse
    37          , s
    38          , string
    39          , top
    40          )
    41  import Url.Parser.Query as Query
    42  
    43  
    44  type Route
    45      = Build { id : Concourse.JobBuildIdentifier, highlight : Highlight }
    46      | Resource { id : Concourse.ResourceIdentifier, page : Maybe Pagination.Page }
    47      | Job { id : Concourse.JobIdentifier, page : Maybe Pagination.Page }
    48      | OneOffBuild { id : Concourse.BuildId, highlight : Highlight }
    49      | Pipeline { id : Concourse.PipelineIdentifier, groups : List String }
    50      | Dashboard { searchType : SearchType, dashboardView : DashboardView }
    51      | FlySuccess Bool (Maybe Int)
    52  
    53  
    54  type SearchType
    55      = HighDensity
    56      | Normal String
    57  
    58  
    59  type DashboardView
    60      = ViewNonArchivedPipelines
    61      | ViewAllPipelines
    62  
    63  
    64  dashboardViews : List DashboardView
    65  dashboardViews =
    66      [ ViewNonArchivedPipelines, ViewAllPipelines ]
    67  
    68  
    69  dashboardViewName : DashboardView -> String
    70  dashboardViewName view =
    71      case view of
    72          ViewAllPipelines ->
    73              "all"
    74  
    75          ViewNonArchivedPipelines ->
    76              "non_archived"
    77  
    78  
    79  type Highlight
    80      = HighlightNothing
    81      | HighlightLine StepID Int
    82      | HighlightRange StepID Int Int
    83  
    84  
    85  type alias StepID =
    86      String
    87  
    88  
    89  type alias Transition =
    90      { from : Route
    91      , to : Route
    92      }
    93  
    94  
    95  
    96  -- pages
    97  
    98  
    99  build : Parser (Route -> a) a
   100  build =
   101      let
   102          buildHelper teamName pipelineName jobName buildName h =
   103              Build
   104                  { id =
   105                      { teamName = teamName
   106                      , pipelineName = pipelineName
   107                      , jobName = jobName
   108                      , buildName = buildName
   109                      }
   110                  , highlight = h
   111                  }
   112      in
   113      map buildHelper
   114          (s "teams"
   115              </> string
   116              </> s "pipelines"
   117              </> string
   118              </> s "jobs"
   119              </> string
   120              </> s "builds"
   121              </> string
   122              </> fragment parseHighlight
   123          )
   124  
   125  
   126  oneOffBuild : Parser (Route -> a) a
   127  oneOffBuild =
   128      map
   129          (\b h -> OneOffBuild { id = b, highlight = h })
   130          (s "builds" </> int </> fragment parseHighlight)
   131  
   132  
   133  parsePage : Maybe Int -> Maybe Int -> Maybe Int -> Maybe Pagination.Page
   134  parsePage from to limit =
   135      case ( from, to, limit ) of
   136          ( Nothing, Just t, Just l ) ->
   137              Just
   138                  { direction = Pagination.To t
   139                  , limit = l
   140                  }
   141  
   142          ( Just f, Nothing, Just l ) ->
   143              Just
   144                  { direction = Pagination.From f
   145                  , limit = l
   146                  }
   147  
   148          _ ->
   149              Nothing
   150  
   151  
   152  resource : Parser (Route -> a) a
   153  resource =
   154      let
   155          resourceHelper teamName pipelineName resourceName from to limit =
   156              Resource
   157                  { id =
   158                      { teamName = teamName
   159                      , pipelineName = pipelineName
   160                      , resourceName = resourceName
   161                      }
   162                  , page = parsePage from to limit
   163                  }
   164      in
   165      map resourceHelper
   166          (s "teams"
   167              </> string
   168              </> s "pipelines"
   169              </> string
   170              </> s "resources"
   171              </> string
   172              <?> Query.int "from"
   173              <?> Query.int "to"
   174              <?> Query.int "limit"
   175          )
   176  
   177  
   178  job : Parser (Route -> a) a
   179  job =
   180      let
   181          jobHelper teamName pipelineName jobName from to limit =
   182              Job
   183                  { id =
   184                      { teamName = teamName
   185                      , pipelineName = pipelineName
   186                      , jobName = jobName
   187                      }
   188                  , page = parsePage from to limit
   189                  }
   190      in
   191      map jobHelper
   192          (s "teams"
   193              </> string
   194              </> s "pipelines"
   195              </> string
   196              </> s "jobs"
   197              </> string
   198              <?> Query.int "from"
   199              <?> Query.int "to"
   200              <?> Query.int "limit"
   201          )
   202  
   203  
   204  pipeline : Parser (Route -> a) a
   205  pipeline =
   206      map
   207          (\t p g ->
   208              Pipeline
   209                  { id =
   210                      { teamName = t
   211                      , pipelineName = p
   212                      }
   213                  , groups = g
   214                  }
   215          )
   216          (s "teams"
   217              </> string
   218              </> s "pipelines"
   219              </> string
   220              <?> Query.custom "group" identity
   221          )
   222  
   223  
   224  dashboard : Parser (Route -> a) a
   225  dashboard =
   226      map (\st view -> Dashboard { searchType = st, dashboardView = view }) <|
   227          oneOf
   228              [ (top <?> Query.string "search")
   229                  |> map
   230                      (Maybe.map (String.replace "+" " ")
   231                          -- https://github.com/elm/url/issues/32
   232                          >> Maybe.withDefault ""
   233                          >> Normal
   234                      )
   235              , s "hd" |> map HighDensity
   236              ]
   237              <?> dashboardViewQuery
   238  
   239  
   240  dashboardViewQuery : Query.Parser DashboardView
   241  dashboardViewQuery =
   242      (Query.enum "view" <|
   243          Dict.fromList
   244              (dashboardViews
   245                  |> List.map (\v -> ( dashboardViewName v, v ))
   246              )
   247      )
   248          |> Query.map (Maybe.withDefault ViewNonArchivedPipelines)
   249  
   250  
   251  flySuccess : Parser (Route -> a) a
   252  flySuccess =
   253      map (\s -> FlySuccess (s == Just "true"))
   254          (s "fly_success"
   255              <?> Query.string "noop"
   256              <?> Query.int "fly_port"
   257          )
   258  
   259  
   260  
   261  -- route utils
   262  
   263  
   264  buildRoute : Int -> String -> Maybe Concourse.JobIdentifier -> Route
   265  buildRoute id name jobId =
   266      case jobId of
   267          Just j ->
   268              Build
   269                  { id =
   270                      { teamName = j.teamName
   271                      , pipelineName = j.pipelineName
   272                      , jobName = j.jobName
   273                      , buildName = name
   274                      }
   275                  , highlight = HighlightNothing
   276                  }
   277  
   278          Nothing ->
   279              OneOffBuild { id = id, highlight = HighlightNothing }
   280  
   281  
   282  jobRoute : Concourse.Job -> Route
   283  jobRoute j =
   284      Job
   285          { id =
   286              { teamName = j.teamName
   287              , pipelineName = j.pipelineName
   288              , jobName = j.name
   289              }
   290          , page = Nothing
   291          }
   292  
   293  
   294  pipelineRoute : { a | name : String, teamName : String } -> Route
   295  pipelineRoute p =
   296      Pipeline { id = { teamName = p.teamName, pipelineName = p.name }, groups = [] }
   297  
   298  
   299  showHighlight : Highlight -> String
   300  showHighlight hl =
   301      case hl of
   302          HighlightNothing ->
   303              ""
   304  
   305          HighlightLine id line ->
   306              "#L" ++ id ++ ":" ++ String.fromInt line
   307  
   308          HighlightRange id line1 line2 ->
   309              "#L"
   310                  ++ id
   311                  ++ ":"
   312                  ++ String.fromInt line1
   313                  ++ ":"
   314                  ++ String.fromInt line2
   315  
   316  
   317  parseHighlight : Maybe String -> Highlight
   318  parseHighlight hash =
   319      case hash of
   320          Just h ->
   321              case String.uncons h of
   322                  Just ( 'L', selector ) ->
   323                      case String.split ":" selector of
   324                          [ stepID, line1str, line2str ] ->
   325                              case ( String.toInt line1str, String.toInt line2str ) of
   326                                  ( Just line1, Just line2 ) ->
   327                                      HighlightRange stepID line1 line2
   328  
   329                                  _ ->
   330                                      HighlightNothing
   331  
   332                          [ stepID, linestr ] ->
   333                              case String.toInt linestr of
   334                                  Just line ->
   335                                      HighlightLine stepID line
   336  
   337                                  _ ->
   338                                      HighlightNothing
   339  
   340                          _ ->
   341                              HighlightNothing
   342  
   343                  _ ->
   344                      HighlightNothing
   345  
   346          _ ->
   347              HighlightNothing
   348  
   349  
   350  tokenToFlyRoute : String -> Int -> String
   351  tokenToFlyRoute authToken flyPort =
   352      Builder.crossOrigin
   353          ("http://127.0.0.1:" ++ String.fromInt flyPort)
   354          []
   355          [ Builder.string "token" authToken ]
   356  
   357  
   358  
   359  -- router
   360  
   361  
   362  sitemap : Parser (Route -> a) a
   363  sitemap =
   364      oneOf
   365          [ resource
   366          , job
   367          , dashboard
   368          , pipeline
   369          , build
   370          , oneOffBuild
   371          , flySuccess
   372          ]
   373  
   374  
   375  toString : Route -> String
   376  toString route =
   377      case route of
   378          Build { id, highlight } ->
   379              Builder.absolute
   380                  [ "teams"
   381                  , id.teamName
   382                  , "pipelines"
   383                  , id.pipelineName
   384                  , "jobs"
   385                  , id.jobName
   386                  , "builds"
   387                  , id.buildName
   388                  ]
   389                  []
   390                  ++ showHighlight highlight
   391  
   392          Job { id, page } ->
   393              Builder.absolute
   394                  [ "teams"
   395                  , id.teamName
   396                  , "pipelines"
   397                  , id.pipelineName
   398                  , "jobs"
   399                  , id.jobName
   400                  ]
   401                  (Api.Pagination.params page)
   402  
   403          Resource { id, page } ->
   404              Builder.absolute
   405                  [ "teams"
   406                  , id.teamName
   407                  , "pipelines"
   408                  , id.pipelineName
   409                  , "resources"
   410                  , id.resourceName
   411                  ]
   412                  (Api.Pagination.params page)
   413  
   414          OneOffBuild { id, highlight } ->
   415              Builder.absolute
   416                  [ "builds"
   417                  , String.fromInt id
   418                  ]
   419                  []
   420                  ++ showHighlight highlight
   421  
   422          Pipeline { id, groups } ->
   423              Builder.absolute
   424                  [ "teams"
   425                  , id.teamName
   426                  , "pipelines"
   427                  , id.pipelineName
   428                  ]
   429                  (groups |> List.map (Builder.string "group"))
   430  
   431          Dashboard { searchType, dashboardView } ->
   432              let
   433                  path =
   434                      case searchType of
   435                          Normal _ ->
   436                              []
   437  
   438                          HighDensity ->
   439                              [ "hd" ]
   440  
   441                  queryParams =
   442                      (case searchType of
   443                          Normal "" ->
   444                              []
   445  
   446                          Normal query ->
   447                              [ Builder.string "search" query ]
   448  
   449                          _ ->
   450                              []
   451                      )
   452                          ++ (case dashboardView of
   453                                  ViewNonArchivedPipelines ->
   454                                      []
   455  
   456                                  _ ->
   457                                      [ Builder.string "view" <| dashboardViewName dashboardView ]
   458                             )
   459              in
   460              Builder.absolute path queryParams
   461  
   462          FlySuccess noop flyPort ->
   463              Builder.absolute [ "fly_success" ] <|
   464                  (flyPort
   465                      |> Maybe.map (Builder.int "fly_port")
   466                      |> Maybe.Extra.toList
   467                  )
   468                      ++ (if noop then
   469                              [ Builder.string "noop" "true" ]
   470  
   471                          else
   472                              []
   473                         )
   474  
   475  
   476  parsePath : Url.Url -> Maybe Route
   477  parsePath =
   478      parse sitemap
   479  
   480  
   481  
   482  -- route utils
   483  
   484  
   485  extractPid : Route -> Maybe Concourse.PipelineIdentifier
   486  extractPid route =
   487      case route of
   488          Build { id } ->
   489              Just { teamName = id.teamName, pipelineName = id.pipelineName }
   490  
   491          Job { id } ->
   492              Just { teamName = id.teamName, pipelineName = id.pipelineName }
   493  
   494          Resource { id } ->
   495              Just { teamName = id.teamName, pipelineName = id.pipelineName }
   496  
   497          Pipeline { id } ->
   498              Just id
   499  
   500          _ ->
   501              Nothing
   502  
   503  
   504  extractQuery : SearchType -> String
   505  extractQuery route =
   506      case route of
   507          Normal q ->
   508              q
   509  
   510          _ ->
   511              ""