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 ""