Refactor route structure (#219)

This commit is contained in:
Marek Fajkus 2020-10-30 19:13:55 +01:00 committed by GitHub
parent 2de4ef3bda
commit fe04d9b14e
Failed to generate hash of commit
6 changed files with 167 additions and 252 deletions

View file

@ -162,15 +162,27 @@ changeRouteTo currentModel url =
let let
attempteQuery (( newModel, cmd ) as pair) = attempteQuery (( newModel, cmd ) as pair) =
case ( currentModel.route, newModel.route ) of case ( currentModel.route, newModel.route ) of
( Route.Packages channel1 query1 _ from1 size1 sort1, Route.Packages channel2 query2 _ from2 size2 sort2 ) -> ( Route.Packages arg1, Route.Packages arg2 ) ->
if channel1 /= channel2 || query1 /= query2 || from1 /= from2 || size1 /= size2 || sort1 /= sort2 then if
(arg1.channel /= arg2.channel)
|| (arg1.query /= arg2.query)
|| (arg1.from /= arg2.from)
|| (arg1.size /= arg2.size)
|| (arg1.sort /= arg2.sort)
then
submitQuery newModel ( newModel, cmd ) submitQuery newModel ( newModel, cmd )
else else
pair pair
( Route.Options channel1 query1 _ from1 size1 sort1, Route.Options channel2 query2 _ from2 size2 sort2 ) -> ( Route.Options arg1, Route.Options arg2 ) ->
if channel1 /= channel2 || query1 /= query2 || from1 /= from2 || size1 /= size2 || sort1 /= sort2 then if
(arg1.channel /= arg2.channel)
|| (arg1.query /= arg2.query)
|| (arg1.from /= arg2.from)
|| (arg1.size /= arg2.size)
|| (arg1.sort /= arg2.sort)
then
submitQuery newModel ( newModel, cmd ) submitQuery newModel ( newModel, cmd )
else else
@ -203,7 +215,7 @@ changeRouteTo currentModel url =
-- on the home page -- on the home page
( model, Browser.Navigation.pushUrl model.navKey "/packages" ) ( model, Browser.Navigation.pushUrl model.navKey "/packages" )
Route.Packages channel query show from size sort -> Route.Packages searchArgs ->
let let
modelPage = modelPage =
case model.page of case model.page of
@ -213,11 +225,11 @@ changeRouteTo currentModel url =
_ -> _ ->
Nothing Nothing
in in
Page.Packages.init channel query show from size sort modelPage Page.Packages.init searchArgs modelPage
|> updateWith Packages PackagesMsg model |> updateWith Packages PackagesMsg model
|> attempteQuery |> attempteQuery
Route.Options channel query show from size sort -> Route.Options searchArgs ->
let let
modelPage = modelPage =
case model.page of case model.page of
@ -227,7 +239,7 @@ changeRouteTo currentModel url =
_ -> _ ->
Nothing Nothing
in in
Page.Options.init channel query show from size sort modelPage Page.Options.init searchArgs modelPage
|> updateWith Options OptionsMsg model |> updateWith Options OptionsMsg model
|> attempteQuery |> attempteQuery
@ -349,14 +361,14 @@ viewNavigation route =
toRoute f = toRoute f =
case route of case route of
-- Preserve arguments -- Preserve arguments
Route.Packages channel query show from size sort -> Route.Packages searchArgs ->
f channel query show from size sort f searchArgs
Route.Options channel query show from size sort -> Route.Options searchArgs ->
f channel query show from size sort f searchArgs
_ -> _ ->
f Nothing Nothing Nothing Nothing Nothing Nothing f <| Route.SearchArgs Nothing Nothing Nothing Nothing Nothing Nothing
in in
li [] [ a [ href "https://nixos.org" ] [ text "Back to nixos.org" ] ] li [] [ a [ href "https://nixos.org" ] [ text "Back to nixos.org" ] ]
:: List.map :: List.map

View file

@ -65,19 +65,11 @@ type alias ResultItemSource =
} }
init : init : Route.SearchArgs -> Maybe Model -> ( Model, Cmd Msg )
Maybe String init searchArgs model =
-> Maybe String
-> Maybe String
-> Maybe Int
-> Maybe Int
-> Maybe String
-> Maybe Model
-> ( Model, Cmd Msg )
init channel query show from size sort model =
let let
( newModel, newCmd ) = ( newModel, newCmd ) =
Search.init channel query show from size sort model Search.init searchArgs model
in in
( newModel ( newModel
, Cmd.map SearchMsg newCmd , Cmd.map SearchMsg newCmd

View file

@ -102,19 +102,11 @@ type alias ResultPackageHydraPath =
} }
init : init : Route.SearchArgs -> Maybe Model -> ( Model, Cmd Msg )
Maybe String init searchArgs model =
-> Maybe String
-> Maybe String
-> Maybe Int
-> Maybe Int
-> Maybe String
-> Maybe Model
-> ( Model, Cmd Msg )
init channel query show from size sort model =
let let
( newModel, newCmd ) = ( newModel, newCmd ) =
Search.init channel query show from size sort model Search.init searchArgs model
in in
( newModel ( newModel
, Cmd.map SearchMsg newCmd , Cmd.map SearchMsg newCmd

View file

@ -1,12 +1,20 @@
module Route exposing (Route(..), fromUrl, href, replaceUrl, routeToString) module Route exposing
( Route(..)
, SearchArgs
, SearchRoute
, fromUrl
, href
, replaceUrl
, routeToString
)
import Browser.Navigation import Browser.Navigation
import Html import Html
import Html.Attributes import Html.Attributes
import Route.SearchQuery import Route.SearchQuery exposing (SearchQuery)
import Url import Url
import Url.Builder exposing (QueryParameter) import Url.Builder exposing (QueryParameter)
import Url.Parser exposing ((<?>)) import Url.Parser exposing ((</>), (<?>))
import Url.Parser.Query import Url.Parser.Query
@ -14,45 +22,66 @@ import Url.Parser.Query
-- ROUTING -- ROUTING
type Route type alias SearchArgs =
= NotFound { query : Maybe SearchQuery
| Home , channel : Maybe String
-- route | channel | (search) query | show | from | size | sort , show : Maybe String
| Packages (Maybe String) (Maybe String) (Maybe String) (Maybe Int) (Maybe Int) (Maybe String) , from : Maybe Int
| Options (Maybe String) (Maybe String) (Maybe String) (Maybe Int) (Maybe Int) (Maybe String) , size : Maybe Int
-- TODO: embed sort type
, sort : Maybe String
}
parser : Url.Url -> Url.Parser.Parser (Route -> msg) msg type alias SearchRoute =
parser url = SearchArgs -> Route
searchQueryParser : Url.Url -> Url.Parser.Parser (SearchArgs -> msg) msg
searchQueryParser url =
let let
rawQuery = rawQuery =
Route.SearchQuery.toRawQuery url Route.SearchQuery.toRawQuery url
withSearchQuery : (a -> Maybe String -> b) -> a -> b maybeQuery = Maybe.andThen (Route.SearchQuery.searchString "query") rawQuery
withSearchQuery f channel =
f channel <|
Maybe.andThen Route.SearchQuery.searchQueryToString <|
Maybe.andThen (Route.SearchQuery.searchString "query") rawQuery
in in
Url.Parser.map (SearchArgs maybeQuery) <|
Url.Parser.top
<?> Url.Parser.Query.string "channel"
<?> Url.Parser.Query.string "show"
<?> Url.Parser.Query.int "from"
<?> Url.Parser.Query.int "size"
<?> Url.Parser.Query.string "sort"
searchArgsToUrl : SearchArgs -> ( List QueryParameter, Maybe ( String, Route.SearchQuery.SearchQuery ) )
searchArgsToUrl args =
( List.filterMap identity
[ Maybe.map (Url.Builder.string "channel") args.channel
, Maybe.map (Url.Builder.string "show") args.show
, Maybe.map (Url.Builder.int "from") args.from
, Maybe.map (Url.Builder.int "size") args.size
, Maybe.map (Url.Builder.string "sort") args.sort
]
, Maybe.map (Tuple.pair "query") args.query
)
type Route
= NotFound
| Home
| Packages SearchArgs
| Options SearchArgs
parser : Url.Url -> Url.Parser.Parser (Route -> msg) msg
parser url =
Url.Parser.oneOf Url.Parser.oneOf
[ Url.Parser.map Home Url.Parser.top [ Url.Parser.map Home Url.Parser.top
, Url.Parser.map NotFound (Url.Parser.s "not-found") , Url.Parser.map NotFound <| Url.Parser.s "not-found"
, Url.Parser.map (withSearchQuery Packages) , Url.Parser.map Packages <| Url.Parser.s "packages" </> searchQueryParser url
(Url.Parser.s "packages" , Url.Parser.map Options <| Url.Parser.s "options" </> searchQueryParser url
<?> Url.Parser.Query.string "channel"
<?> Url.Parser.Query.string "show"
<?> Url.Parser.Query.int "from"
<?> Url.Parser.Query.int "size"
<?> Url.Parser.Query.string "sort"
)
, Url.Parser.map (withSearchQuery Options)
(Url.Parser.s "options"
<?> Url.Parser.Query.string "channel"
<?> Url.Parser.Query.string "show"
<?> Url.Parser.Query.int "from"
<?> Url.Parser.Query.int "size"
<?> Url.Parser.Query.string "sort"
)
] ]
@ -96,51 +125,17 @@ routeToString =
routeToPieces : Route -> ( List String, List QueryParameter, Maybe ( String, Route.SearchQuery.SearchQuery ) ) routeToPieces : Route -> ( List String, List QueryParameter, Maybe ( String, Route.SearchQuery.SearchQuery ) )
routeToPieces page = routeToPieces page =
let case page of
channelQ = Home ->
Maybe.map (Url.Builder.string "channel") ( [], [], Nothing )
queryQ = NotFound ->
Maybe.map (Route.SearchQuery.toSearchQuery "query") ( [ "not-found" ], [], Nothing )
showQ = Packages searchArgs ->
Maybe.map (Url.Builder.string "show") searchArgsToUrl searchArgs
|> (\( query, raw ) -> ( [ "packages" ], query, raw ))
fromQ = Options searchArgs ->
Maybe.map (Url.Builder.int "from") searchArgsToUrl searchArgs
|> (\( query, raw ) -> ( [ "options" ], query, raw ))
sizeQ =
Maybe.map (Url.Builder.int "size")
sortQ =
Maybe.map (Url.Builder.string "sort")
in
(\( path, urlQ, searchQuery ) -> ( path, List.filterMap identity urlQ, searchQuery )) <|
case page of
Home ->
( [], [], Nothing )
NotFound ->
( [ "not-found" ], [], Nothing )
Packages channel query show from size sort ->
( [ "packages" ]
, [ channelQ channel
, showQ show
, fromQ from
, sizeQ size
, sortQ sort
]
, queryQ query
)
Options channel query show from size sort ->
( [ "options" ]
, [ channelQ channel
, showQ show
, fromQ from
, sizeQ size
, sortQ sort
]
, queryQ query
)

View file

@ -60,9 +60,9 @@ searchQueryToString (SearchQuery str) =
Url.percentDecode <| String.replace "+" "%20" str Url.percentDecode <| String.replace "+" "%20" str
toSearchQuery : String -> String -> ( String, SearchQuery ) toSearchQuery : String -> SearchQuery
toSearchQuery name query = toSearchQuery query =
( name, SearchQuery <| String.replace "%20" "+" <| Url.percentEncode query ) SearchQuery <| String.replace "%20" "+" <| Url.percentEncode query
{-| Build absolute URL with support for search query strings {-| Build absolute URL with support for search query strings

View file

@ -63,22 +63,13 @@ import Json.Decode
import Json.Encode import Json.Encode
import RemoteData import RemoteData
import Route exposing (Route) import Route exposing (Route)
import Route.SearchQuery
import Set import Set
import Task import Task
import Url import Url
import Url.Builder import Url.Builder
type alias SearchRoute =
Maybe String
-> Maybe String
-> Maybe String
-> Maybe Int
-> Maybe Int
-> Maybe String
-> Route
type alias Model a = type alias Model a =
{ channel : String { channel : String
, query : Maybe String , query : Maybe String
@ -124,16 +115,8 @@ type Sort
| AlphabeticallyDesc | AlphabeticallyDesc
init : init : Route.SearchArgs -> Maybe (Model a) -> ( Model a, Cmd (Msg a) )
Maybe String init args model =
-> Maybe String
-> Maybe String
-> Maybe Int
-> Maybe Int
-> Maybe String
-> Maybe (Model a)
-> ( Model a, Cmd (Msg a) )
init channel query show from size sort model =
let let
defaultChannel = defaultChannel =
model model
@ -150,17 +133,17 @@ init channel query show from size sort model =
|> Maybe.map (\x -> x.size) |> Maybe.map (\x -> x.size)
|> Maybe.withDefault 30 |> Maybe.withDefault 30
in in
( { channel = Maybe.withDefault defaultChannel channel ( { channel = Maybe.withDefault defaultChannel args.channel
, query = query , query = Maybe.andThen Route.SearchQuery.searchQueryToString args.query
, result = , result =
model model
|> Maybe.map (\x -> x.result) |> Maybe.map (\x -> x.result)
|> Maybe.withDefault RemoteData.NotAsked |> Maybe.withDefault RemoteData.NotAsked
, show = show , show = args.show
, from = Maybe.withDefault defaultFrom from , from = Maybe.withDefault defaultFrom args.from
, size = Maybe.withDefault defaultSize size , size = Maybe.withDefault defaultSize args.size
, sort = , sort =
sort args.sort
|> Maybe.withDefault "" |> Maybe.withDefault ""
|> fromSortId |> fromSortId
|> Maybe.withDefault Relevance |> Maybe.withDefault Relevance
@ -186,7 +169,7 @@ type Msg a
update : update :
SearchRoute Route.SearchRoute
-> Browser.Navigation.Key -> Browser.Navigation.Key
-> Msg a -> Msg a
-> Model a -> Model a
@ -199,24 +182,14 @@ update toRoute navKey msg model =
) )
SortChange sortId -> SortChange sortId ->
let { model
sort = | sort = fromSortId sortId |> Maybe.withDefault Relevance
fromSortId sortId |> Maybe.withDefault Relevance , from = 0
in }
( { model | sort = sort } |> pushUrl toRoute navKey
, createUrl
toRoute
model.channel
model.query
model.show
0
model.size
sort
|> Browser.Navigation.pushUrl navKey
)
ChannelChange channel -> ChannelChange channel ->
( { model { model
| channel = channel | channel = channel
, result = , result =
if model.query == Nothing || model.query == Just "" then if model.query == Nothing || model.query == Just "" then
@ -224,21 +197,9 @@ update toRoute navKey msg model =
else else
RemoteData.Loading RemoteData.Loading
} , from = 0
, if model.query == Nothing || model.query == Just "" then }
Cmd.none |> pushUrl toRoute navKey
else
createUrl
toRoute
channel
model.query
model.show
0
model.size
model.sort
|> Browser.Navigation.pushUrl navKey
)
QueryInput query -> QueryInput query ->
( { model | query = Just query } ( { model | query = Just query }
@ -246,21 +207,11 @@ update toRoute navKey msg model =
) )
QueryInputSubmit -> QueryInputSubmit ->
if model.query == Nothing || model.query == Just "" then { model
( model, Cmd.none ) | result = RemoteData.Loading
, from = 0
else }
( { model | result = RemoteData.Loading } |> pushUrl toRoute navKey
, createUrl
toRoute
model.channel
model.query
model.show
0
model.size
model.sort
|> Browser.Navigation.pushUrl navKey
)
QueryResponse result -> QueryResponse result ->
( { model | result = result } ( { model | result = result }
@ -268,38 +219,38 @@ update toRoute navKey msg model =
) )
ShowDetails selected -> ShowDetails selected ->
( model { model
, createUrl | show =
toRoute if model.show == Just selected then
model.channel Nothing
model.query
(if model.show == Just selected then
Nothing
else else
Just selected Just selected
) }
model.from |> pushUrl toRoute navKey
model.size
model.sort
|> Browser.Navigation.pushUrl navKey
)
{-| TODO: Sort should be part of Route type pushUrl : Route.SearchRoute -> Browser.Navigation.Key -> Model a -> ( Model a, Cmd msg )
-} pushUrl toRoute navKey model =
createUrl : Tuple.pair model <|
SearchRoute if model.query == Nothing || model.query == Just "" then
-> String Cmd.none
-> Maybe String
-> Maybe String else
-> Int Browser.Navigation.pushUrl navKey <| createUrl toRoute model
-> Int
-> Sort
-> String createUrl : Route.SearchRoute -> Model a -> String
createUrl toRoute channel query show from size sort = createUrl toRoute model =
toRoute (Just channel) query show (Just from) (Just size) (Just <| toSortId sort) Route.routeToString <|
|> Route.routeToString toRoute
{ channel = Just model.channel
, query = Maybe.map Route.SearchQuery.toSearchQuery model.query
, show = model.show
, from = Just model.from
, size = Just model.size
, sort = Just <| toSortId model.sort
}
@ -448,7 +399,7 @@ fromSortId id =
view : view :
{ toRoute : SearchRoute { toRoute : Route.SearchRoute
, categoryName : String , categoryName : String
} }
-> String -> String
@ -624,7 +575,7 @@ viewPager :
(Msg a -> b) (Msg a -> b)
-> Model a -> Model a
-> SearchResult a -> SearchResult a
-> SearchRoute -> Route.SearchRoute
-> Html b -> Html b
viewPager _ model result toRoute = viewPager _ model result toRoute =
ul [ class "pager" ] ul [ class "pager" ]
@ -639,14 +590,7 @@ viewPager _ model result toRoute =
"" ""
else else
createUrl createUrl toRoute { model | from = 0 }
toRoute
model.channel
model.query
model.show
0
model.size
model.sort
] ]
[ text "First" ] [ text "First" ]
] ]
@ -661,14 +605,7 @@ viewPager _ model result toRoute =
"" ""
else else
createUrl createUrl toRoute { model | from = model.from - model.size }
toRoute
model.channel
model.query
model.show
(model.from - model.size)
model.size
model.sort
] ]
[ text "Previous" ] [ text "Previous" ]
] ]
@ -683,14 +620,7 @@ viewPager _ model result toRoute =
"" ""
else else
createUrl createUrl toRoute { model | from = model.from + model.size }
toRoute
model.channel
model.query
model.show
(model.from + model.size)
model.size
model.sort
] ]
[ text "Next" ] [ text "Next" ]
] ]
@ -713,14 +643,8 @@ viewPager _ model result toRoute =
else else
0 0
in in
createUrl createUrl toRoute
toRoute { model | from = ((result.hits.total.value // model.size) - remainder) * model.size }
model.channel
model.query
model.show
(((result.hits.total.value // model.size) - remainder) * model.size)
model.size
model.sort
] ]
[ text "Last" ] [ text "Last" ]
] ]