Refactor route structure (#219)
This commit is contained in:
parent
2de4ef3bda
commit
fe04d9b14e
38
src/Main.elm
38
src/Main.elm
|
@ -162,15 +162,27 @@ changeRouteTo currentModel url =
|
|||
let
|
||||
attempteQuery (( newModel, cmd ) as pair) =
|
||||
case ( currentModel.route, newModel.route ) of
|
||||
( Route.Packages channel1 query1 _ from1 size1 sort1, Route.Packages channel2 query2 _ from2 size2 sort2 ) ->
|
||||
if channel1 /= channel2 || query1 /= query2 || from1 /= from2 || size1 /= size2 || sort1 /= sort2 then
|
||||
( Route.Packages arg1, Route.Packages arg2 ) ->
|
||||
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 )
|
||||
|
||||
else
|
||||
pair
|
||||
|
||||
( Route.Options channel1 query1 _ from1 size1 sort1, Route.Options channel2 query2 _ from2 size2 sort2 ) ->
|
||||
if channel1 /= channel2 || query1 /= query2 || from1 /= from2 || size1 /= size2 || sort1 /= sort2 then
|
||||
( Route.Options arg1, Route.Options arg2 ) ->
|
||||
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 )
|
||||
|
||||
else
|
||||
|
@ -203,7 +215,7 @@ changeRouteTo currentModel url =
|
|||
-- on the home page
|
||||
( model, Browser.Navigation.pushUrl model.navKey "/packages" )
|
||||
|
||||
Route.Packages channel query show from size sort ->
|
||||
Route.Packages searchArgs ->
|
||||
let
|
||||
modelPage =
|
||||
case model.page of
|
||||
|
@ -213,11 +225,11 @@ changeRouteTo currentModel url =
|
|||
_ ->
|
||||
Nothing
|
||||
in
|
||||
Page.Packages.init channel query show from size sort modelPage
|
||||
Page.Packages.init searchArgs modelPage
|
||||
|> updateWith Packages PackagesMsg model
|
||||
|> attempteQuery
|
||||
|
||||
Route.Options channel query show from size sort ->
|
||||
Route.Options searchArgs ->
|
||||
let
|
||||
modelPage =
|
||||
case model.page of
|
||||
|
@ -227,7 +239,7 @@ changeRouteTo currentModel url =
|
|||
_ ->
|
||||
Nothing
|
||||
in
|
||||
Page.Options.init channel query show from size sort modelPage
|
||||
Page.Options.init searchArgs modelPage
|
||||
|> updateWith Options OptionsMsg model
|
||||
|> attempteQuery
|
||||
|
||||
|
@ -349,14 +361,14 @@ viewNavigation route =
|
|||
toRoute f =
|
||||
case route of
|
||||
-- Preserve arguments
|
||||
Route.Packages channel query show from size sort ->
|
||||
f channel query show from size sort
|
||||
Route.Packages searchArgs ->
|
||||
f searchArgs
|
||||
|
||||
Route.Options channel query show from size sort ->
|
||||
f channel query show from size sort
|
||||
Route.Options searchArgs ->
|
||||
f searchArgs
|
||||
|
||||
_ ->
|
||||
f Nothing Nothing Nothing Nothing Nothing Nothing
|
||||
f <| Route.SearchArgs Nothing Nothing Nothing Nothing Nothing Nothing
|
||||
in
|
||||
li [] [ a [ href "https://nixos.org" ] [ text "Back to nixos.org" ] ]
|
||||
:: List.map
|
||||
|
|
|
@ -65,19 +65,11 @@ type alias ResultItemSource =
|
|||
}
|
||||
|
||||
|
||||
init :
|
||||
Maybe String
|
||||
-> Maybe String
|
||||
-> Maybe String
|
||||
-> Maybe Int
|
||||
-> Maybe Int
|
||||
-> Maybe String
|
||||
-> Maybe Model
|
||||
-> ( Model, Cmd Msg )
|
||||
init channel query show from size sort model =
|
||||
init : Route.SearchArgs -> Maybe Model -> ( Model, Cmd Msg )
|
||||
init searchArgs model =
|
||||
let
|
||||
( newModel, newCmd ) =
|
||||
Search.init channel query show from size sort model
|
||||
Search.init searchArgs model
|
||||
in
|
||||
( newModel
|
||||
, Cmd.map SearchMsg newCmd
|
||||
|
|
|
@ -102,19 +102,11 @@ type alias ResultPackageHydraPath =
|
|||
}
|
||||
|
||||
|
||||
init :
|
||||
Maybe String
|
||||
-> Maybe String
|
||||
-> Maybe String
|
||||
-> Maybe Int
|
||||
-> Maybe Int
|
||||
-> Maybe String
|
||||
-> Maybe Model
|
||||
-> ( Model, Cmd Msg )
|
||||
init channel query show from size sort model =
|
||||
init : Route.SearchArgs -> Maybe Model -> ( Model, Cmd Msg )
|
||||
init searchArgs model =
|
||||
let
|
||||
( newModel, newCmd ) =
|
||||
Search.init channel query show from size sort model
|
||||
Search.init searchArgs model
|
||||
in
|
||||
( newModel
|
||||
, Cmd.map SearchMsg newCmd
|
||||
|
|
141
src/Route.elm
141
src/Route.elm
|
@ -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 Html
|
||||
import Html.Attributes
|
||||
import Route.SearchQuery
|
||||
import Route.SearchQuery exposing (SearchQuery)
|
||||
import Url
|
||||
import Url.Builder exposing (QueryParameter)
|
||||
import Url.Parser exposing ((<?>))
|
||||
import Url.Parser exposing ((</>), (<?>))
|
||||
import Url.Parser.Query
|
||||
|
||||
|
||||
|
@ -14,45 +22,66 @@ import Url.Parser.Query
|
|||
-- ROUTING
|
||||
|
||||
|
||||
type Route
|
||||
= NotFound
|
||||
| Home
|
||||
-- route | channel | (search) query | show | from | size | sort
|
||||
| Packages (Maybe String) (Maybe String) (Maybe String) (Maybe Int) (Maybe Int) (Maybe String)
|
||||
| Options (Maybe String) (Maybe String) (Maybe String) (Maybe Int) (Maybe Int) (Maybe String)
|
||||
type alias SearchArgs =
|
||||
{ query : Maybe SearchQuery
|
||||
, channel : Maybe String
|
||||
, show : Maybe String
|
||||
, from : Maybe Int
|
||||
, size : Maybe Int
|
||||
|
||||
-- TODO: embed sort type
|
||||
, sort : Maybe String
|
||||
}
|
||||
|
||||
|
||||
parser : Url.Url -> Url.Parser.Parser (Route -> msg) msg
|
||||
parser url =
|
||||
type alias SearchRoute =
|
||||
SearchArgs -> Route
|
||||
|
||||
|
||||
searchQueryParser : Url.Url -> Url.Parser.Parser (SearchArgs -> msg) msg
|
||||
searchQueryParser url =
|
||||
let
|
||||
rawQuery =
|
||||
Route.SearchQuery.toRawQuery url
|
||||
|
||||
withSearchQuery : (a -> Maybe String -> b) -> a -> b
|
||||
withSearchQuery f channel =
|
||||
f channel <|
|
||||
Maybe.andThen Route.SearchQuery.searchQueryToString <|
|
||||
Maybe.andThen (Route.SearchQuery.searchString "query") rawQuery
|
||||
maybeQuery = Maybe.andThen (Route.SearchQuery.searchString "query") rawQuery
|
||||
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.map Home Url.Parser.top
|
||||
, Url.Parser.map NotFound (Url.Parser.s "not-found")
|
||||
, Url.Parser.map (withSearchQuery Packages)
|
||||
(Url.Parser.s "packages"
|
||||
<?> 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"
|
||||
)
|
||||
, Url.Parser.map NotFound <| Url.Parser.s "not-found"
|
||||
, Url.Parser.map Packages <| Url.Parser.s "packages" </> searchQueryParser url
|
||||
, Url.Parser.map Options <| Url.Parser.s "options" </> searchQueryParser url
|
||||
]
|
||||
|
||||
|
||||
|
@ -96,26 +125,6 @@ routeToString =
|
|||
|
||||
routeToPieces : Route -> ( List String, List QueryParameter, Maybe ( String, Route.SearchQuery.SearchQuery ) )
|
||||
routeToPieces page =
|
||||
let
|
||||
channelQ =
|
||||
Maybe.map (Url.Builder.string "channel")
|
||||
|
||||
queryQ =
|
||||
Maybe.map (Route.SearchQuery.toSearchQuery "query")
|
||||
|
||||
showQ =
|
||||
Maybe.map (Url.Builder.string "show")
|
||||
|
||||
fromQ =
|
||||
Maybe.map (Url.Builder.int "from")
|
||||
|
||||
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 )
|
||||
|
@ -123,24 +132,10 @@ routeToPieces page =
|
|||
NotFound ->
|
||||
( [ "not-found" ], [], Nothing )
|
||||
|
||||
Packages channel query show from size sort ->
|
||||
( [ "packages" ]
|
||||
, [ channelQ channel
|
||||
, showQ show
|
||||
, fromQ from
|
||||
, sizeQ size
|
||||
, sortQ sort
|
||||
]
|
||||
, queryQ query
|
||||
)
|
||||
Packages searchArgs ->
|
||||
searchArgsToUrl searchArgs
|
||||
|> (\( query, raw ) -> ( [ "packages" ], query, raw ))
|
||||
|
||||
Options channel query show from size sort ->
|
||||
( [ "options" ]
|
||||
, [ channelQ channel
|
||||
, showQ show
|
||||
, fromQ from
|
||||
, sizeQ size
|
||||
, sortQ sort
|
||||
]
|
||||
, queryQ query
|
||||
)
|
||||
Options searchArgs ->
|
||||
searchArgsToUrl searchArgs
|
||||
|> (\( query, raw ) -> ( [ "options" ], query, raw ))
|
||||
|
|
|
@ -60,9 +60,9 @@ searchQueryToString (SearchQuery str) =
|
|||
Url.percentDecode <| String.replace "+" "%20" str
|
||||
|
||||
|
||||
toSearchQuery : String -> String -> ( String, SearchQuery )
|
||||
toSearchQuery name query =
|
||||
( name, SearchQuery <| String.replace "%20" "+" <| Url.percentEncode query )
|
||||
toSearchQuery : String -> SearchQuery
|
||||
toSearchQuery query =
|
||||
SearchQuery <| String.replace "%20" "+" <| Url.percentEncode query
|
||||
|
||||
|
||||
{-| Build absolute URL with support for search query strings
|
||||
|
|
188
src/Search.elm
188
src/Search.elm
|
@ -63,22 +63,13 @@ import Json.Decode
|
|||
import Json.Encode
|
||||
import RemoteData
|
||||
import Route exposing (Route)
|
||||
import Route.SearchQuery
|
||||
import Set
|
||||
import Task
|
||||
import Url
|
||||
import Url.Builder
|
||||
|
||||
|
||||
type alias SearchRoute =
|
||||
Maybe String
|
||||
-> Maybe String
|
||||
-> Maybe String
|
||||
-> Maybe Int
|
||||
-> Maybe Int
|
||||
-> Maybe String
|
||||
-> Route
|
||||
|
||||
|
||||
type alias Model a =
|
||||
{ channel : String
|
||||
, query : Maybe String
|
||||
|
@ -124,16 +115,8 @@ type Sort
|
|||
| AlphabeticallyDesc
|
||||
|
||||
|
||||
init :
|
||||
Maybe String
|
||||
-> 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 =
|
||||
init : Route.SearchArgs -> Maybe (Model a) -> ( Model a, Cmd (Msg a) )
|
||||
init args model =
|
||||
let
|
||||
defaultChannel =
|
||||
model
|
||||
|
@ -150,17 +133,17 @@ init channel query show from size sort model =
|
|||
|> Maybe.map (\x -> x.size)
|
||||
|> Maybe.withDefault 30
|
||||
in
|
||||
( { channel = Maybe.withDefault defaultChannel channel
|
||||
, query = query
|
||||
( { channel = Maybe.withDefault defaultChannel args.channel
|
||||
, query = Maybe.andThen Route.SearchQuery.searchQueryToString args.query
|
||||
, result =
|
||||
model
|
||||
|> Maybe.map (\x -> x.result)
|
||||
|> Maybe.withDefault RemoteData.NotAsked
|
||||
, show = show
|
||||
, from = Maybe.withDefault defaultFrom from
|
||||
, size = Maybe.withDefault defaultSize size
|
||||
, show = args.show
|
||||
, from = Maybe.withDefault defaultFrom args.from
|
||||
, size = Maybe.withDefault defaultSize args.size
|
||||
, sort =
|
||||
sort
|
||||
args.sort
|
||||
|> Maybe.withDefault ""
|
||||
|> fromSortId
|
||||
|> Maybe.withDefault Relevance
|
||||
|
@ -186,7 +169,7 @@ type Msg a
|
|||
|
||||
|
||||
update :
|
||||
SearchRoute
|
||||
Route.SearchRoute
|
||||
-> Browser.Navigation.Key
|
||||
-> Msg a
|
||||
-> Model a
|
||||
|
@ -199,24 +182,14 @@ update toRoute navKey msg model =
|
|||
)
|
||||
|
||||
SortChange sortId ->
|
||||
let
|
||||
sort =
|
||||
fromSortId sortId |> Maybe.withDefault Relevance
|
||||
in
|
||||
( { model | sort = sort }
|
||||
, createUrl
|
||||
toRoute
|
||||
model.channel
|
||||
model.query
|
||||
model.show
|
||||
0
|
||||
model.size
|
||||
sort
|
||||
|> Browser.Navigation.pushUrl navKey
|
||||
)
|
||||
{ model
|
||||
| sort = fromSortId sortId |> Maybe.withDefault Relevance
|
||||
, from = 0
|
||||
}
|
||||
|> pushUrl toRoute navKey
|
||||
|
||||
ChannelChange channel ->
|
||||
( { model
|
||||
{ model
|
||||
| channel = channel
|
||||
, result =
|
||||
if model.query == Nothing || model.query == Just "" then
|
||||
|
@ -224,21 +197,9 @@ update toRoute navKey msg model =
|
|||
|
||||
else
|
||||
RemoteData.Loading
|
||||
, from = 0
|
||||
}
|
||||
, if model.query == Nothing || model.query == Just "" then
|
||||
Cmd.none
|
||||
|
||||
else
|
||||
createUrl
|
||||
toRoute
|
||||
channel
|
||||
model.query
|
||||
model.show
|
||||
0
|
||||
model.size
|
||||
model.sort
|
||||
|> Browser.Navigation.pushUrl navKey
|
||||
)
|
||||
|> pushUrl toRoute navKey
|
||||
|
||||
QueryInput query ->
|
||||
( { model | query = Just query }
|
||||
|
@ -246,21 +207,11 @@ update toRoute navKey msg model =
|
|||
)
|
||||
|
||||
QueryInputSubmit ->
|
||||
if model.query == Nothing || model.query == Just "" then
|
||||
( model, Cmd.none )
|
||||
|
||||
else
|
||||
( { model | result = RemoteData.Loading }
|
||||
, createUrl
|
||||
toRoute
|
||||
model.channel
|
||||
model.query
|
||||
model.show
|
||||
0
|
||||
model.size
|
||||
model.sort
|
||||
|> Browser.Navigation.pushUrl navKey
|
||||
)
|
||||
{ model
|
||||
| result = RemoteData.Loading
|
||||
, from = 0
|
||||
}
|
||||
|> pushUrl toRoute navKey
|
||||
|
||||
QueryResponse result ->
|
||||
( { model | result = result }
|
||||
|
@ -268,38 +219,38 @@ update toRoute navKey msg model =
|
|||
)
|
||||
|
||||
ShowDetails selected ->
|
||||
( model
|
||||
, createUrl
|
||||
toRoute
|
||||
model.channel
|
||||
model.query
|
||||
(if model.show == Just selected then
|
||||
{ model
|
||||
| show =
|
||||
if model.show == Just selected then
|
||||
Nothing
|
||||
|
||||
else
|
||||
Just selected
|
||||
)
|
||||
model.from
|
||||
model.size
|
||||
model.sort
|
||||
|> Browser.Navigation.pushUrl navKey
|
||||
)
|
||||
}
|
||||
|> pushUrl toRoute navKey
|
||||
|
||||
|
||||
{-| TODO: Sort should be part of Route type
|
||||
-}
|
||||
createUrl :
|
||||
SearchRoute
|
||||
-> String
|
||||
-> Maybe String
|
||||
-> Maybe String
|
||||
-> Int
|
||||
-> Int
|
||||
-> Sort
|
||||
-> String
|
||||
createUrl toRoute channel query show from size sort =
|
||||
toRoute (Just channel) query show (Just from) (Just size) (Just <| toSortId sort)
|
||||
|> Route.routeToString
|
||||
pushUrl : Route.SearchRoute -> Browser.Navigation.Key -> Model a -> ( Model a, Cmd msg )
|
||||
pushUrl toRoute navKey model =
|
||||
Tuple.pair model <|
|
||||
if model.query == Nothing || model.query == Just "" then
|
||||
Cmd.none
|
||||
|
||||
else
|
||||
Browser.Navigation.pushUrl navKey <| createUrl toRoute model
|
||||
|
||||
|
||||
createUrl : Route.SearchRoute -> Model a -> String
|
||||
createUrl toRoute model =
|
||||
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 :
|
||||
{ toRoute : SearchRoute
|
||||
{ toRoute : Route.SearchRoute
|
||||
, categoryName : String
|
||||
}
|
||||
-> String
|
||||
|
@ -624,7 +575,7 @@ viewPager :
|
|||
(Msg a -> b)
|
||||
-> Model a
|
||||
-> SearchResult a
|
||||
-> SearchRoute
|
||||
-> Route.SearchRoute
|
||||
-> Html b
|
||||
viewPager _ model result toRoute =
|
||||
ul [ class "pager" ]
|
||||
|
@ -639,14 +590,7 @@ viewPager _ model result toRoute =
|
|||
""
|
||||
|
||||
else
|
||||
createUrl
|
||||
toRoute
|
||||
model.channel
|
||||
model.query
|
||||
model.show
|
||||
0
|
||||
model.size
|
||||
model.sort
|
||||
createUrl toRoute { model | from = 0 }
|
||||
]
|
||||
[ text "First" ]
|
||||
]
|
||||
|
@ -661,14 +605,7 @@ viewPager _ model result toRoute =
|
|||
""
|
||||
|
||||
else
|
||||
createUrl
|
||||
toRoute
|
||||
model.channel
|
||||
model.query
|
||||
model.show
|
||||
(model.from - model.size)
|
||||
model.size
|
||||
model.sort
|
||||
createUrl toRoute { model | from = model.from - model.size }
|
||||
]
|
||||
[ text "Previous" ]
|
||||
]
|
||||
|
@ -683,14 +620,7 @@ viewPager _ model result toRoute =
|
|||
""
|
||||
|
||||
else
|
||||
createUrl
|
||||
toRoute
|
||||
model.channel
|
||||
model.query
|
||||
model.show
|
||||
(model.from + model.size)
|
||||
model.size
|
||||
model.sort
|
||||
createUrl toRoute { model | from = model.from + model.size }
|
||||
]
|
||||
[ text "Next" ]
|
||||
]
|
||||
|
@ -713,14 +643,8 @@ viewPager _ model result toRoute =
|
|||
else
|
||||
0
|
||||
in
|
||||
createUrl
|
||||
toRoute
|
||||
model.channel
|
||||
model.query
|
||||
model.show
|
||||
(((result.hits.total.value // model.size) - remainder) * model.size)
|
||||
model.size
|
||||
model.sort
|
||||
createUrl toRoute
|
||||
{ model | from = ((result.hits.total.value // model.size) - remainder) * model.size }
|
||||
]
|
||||
[ text "Last" ]
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue