aux-search/src/Main.elm

411 lines
11 KiB
Elm
Raw Normal View History

module Main exposing (main)
2020-03-28 04:09:01 +00:00
--exposing (UrlRequest(..))
import Browser
import Browser.Navigation
import Html
exposing
( Html
2020-04-10 08:13:50 +00:00
, a
, button
, div
2020-04-10 08:13:50 +00:00
, footer
, header
2020-04-10 08:13:50 +00:00
, img
, li
, span
, text
, ul
)
import Html.Attributes
exposing
( attribute
, class
, classList
2020-04-10 08:13:50 +00:00
, href
, id
2020-04-10 08:13:50 +00:00
, src
, type_
)
import Page.Home
import Page.Options
import Page.Packages
import Route
import Search
import Url
import Url.Builder
2020-03-28 04:09:01 +00:00
-- MODEL
type alias Flags =
{ elasticsearchMappingSchemaVersion : Int
, elasticsearchUrl : String
, elasticsearchUsername : String
, elasticsearchPassword : String
}
2020-03-28 04:09:01 +00:00
type alias Model =
{ navKey : Browser.Navigation.Key
, url : Url.Url
2020-06-03 19:02:12 +00:00
, elasticsearch : Search.Options
2020-03-28 04:09:01 +00:00
, page : Page
}
type Page
= NotFound
| Home Page.Home.Model
| Packages Page.Packages.Model
| Options Page.Options.Model
init :
Flags
-> Url.Url
-> Browser.Navigation.Key
-> ( Model, Cmd Msg )
init flags url navKey =
2020-04-10 08:13:50 +00:00
let
model =
{ navKey = navKey
, url = url
, elasticsearch =
2020-06-03 19:02:12 +00:00
Search.Options
flags.elasticsearchMappingSchemaVersion
flags.elasticsearchUrl
flags.elasticsearchUsername
flags.elasticsearchPassword
, page = NotFound
2020-04-10 08:13:50 +00:00
}
in
changeRouteTo model url
2020-04-10 08:13:50 +00:00
2020-03-28 04:09:01 +00:00
-- UPDATE
type Msg
= ChangedUrl Url.Url
| ClickedLink Browser.UrlRequest
| HomeMsg Page.Home.Msg
| PackagesMsg Page.Packages.Msg
| OptionsMsg Page.Options.Msg
updateWith :
(subModel -> Page)
-> (subMsg -> Msg)
-> Model
-> ( subModel, Cmd subMsg )
-> ( Model, Cmd Msg )
updateWith toPage toMsg model ( subModel, subCmd ) =
( { model | page = toPage subModel }
, Cmd.map toMsg subCmd
)
submitQuery :
Model
-> ( Model, Cmd Msg )
-> ( Model, Cmd Msg )
submitQuery old ( new, cmd ) =
let
triggerSearch _ newModel msg makeRequest =
if newModel.query /= Nothing && newModel.query /= Just "" then
( new
, Cmd.batch
[ cmd
, makeRequest
new.elasticsearch
2020-05-11 20:42:57 +00:00
newModel.channel
(Maybe.withDefault "" newModel.query)
2020-05-11 19:56:10 +00:00
newModel.from
newModel.size
|> Cmd.map msg
]
)
else
( new, cmd )
in
case ( old.page, new.page ) of
( Packages oldModel, Packages newModel ) ->
triggerSearch oldModel newModel PackagesMsg Page.Packages.makeRequest
( NotFound, Packages newModel ) ->
triggerSearch newModel newModel PackagesMsg Page.Packages.makeRequest
( Options oldModel, Options newModel ) ->
triggerSearch oldModel newModel OptionsMsg Page.Options.makeRequest
( NotFound, Options newModel ) ->
triggerSearch newModel newModel OptionsMsg Page.Options.makeRequest
( _, _ ) ->
( new, cmd )
changeRouteTo :
Model
-> Url.Url
-> ( Model, Cmd Msg )
changeRouteTo model url =
let
newModel =
{ model | url = url }
maybeRoute =
Route.fromUrl url
in
case maybeRoute of
Nothing ->
( { newModel
| page = NotFound
}
, Cmd.none
)
Just Route.NotFound ->
( { newModel
| page = NotFound
}
, Cmd.none
)
Just Route.Home ->
-- Always redirect to /packages until we have something to show
-- on the home page
( newModel, Browser.Navigation.pushUrl newModel.navKey "/packages" )
Just (Route.Packages channel query show from size) ->
let
modelPage =
case newModel.page of
Packages x ->
Just x
_ ->
Nothing
in
Page.Packages.init channel query show from size modelPage
|> updateWith Packages PackagesMsg newModel
|> submitQuery newModel
Just (Route.Options channel query show from size) ->
let
modelPage =
case newModel.page of
Options x ->
Just x
_ ->
Nothing
in
Page.Options.init channel query show from size modelPage
|> updateWith Options OptionsMsg newModel
|> submitQuery newModel
2020-03-28 04:09:01 +00:00
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case ( msg, model.page ) of
( ClickedLink urlRequest, _ ) ->
case urlRequest of
Browser.Internal url ->
2020-03-31 00:59:06 +00:00
( model
2020-05-11 19:56:10 +00:00
, if url.fragment == Just "disabled" then
Cmd.none
else
Browser.Navigation.pushUrl model.navKey <| Url.toString url
2020-03-31 00:59:06 +00:00
)
2020-03-28 04:09:01 +00:00
Browser.External href ->
2020-04-10 08:13:50 +00:00
( model
, Browser.Navigation.load href
2020-04-10 08:13:50 +00:00
)
( ChangedUrl url, _ ) ->
changeRouteTo model url
2020-04-10 08:13:50 +00:00
( HomeMsg subMsg, Home subModel ) ->
Page.Home.update subMsg subModel
|> updateWith Home HomeMsg model
( PackagesMsg subMsg, Packages subModel ) ->
2020-07-02 12:27:49 +00:00
Page.Packages.update model.navKey model.elasticsearch subMsg subModel
|> updateWith Packages PackagesMsg model
( OptionsMsg subMsg, Options subModel ) ->
2020-07-02 12:27:49 +00:00
Page.Options.update model.navKey model.elasticsearch subMsg subModel
|> updateWith Options OptionsMsg model
( _, _ ) ->
-- Disregard messages that arrived for the wrong page.
( model, Cmd.none )
2020-04-10 08:13:50 +00:00
2020-03-28 04:09:01 +00:00
-- VIEW
view :
Model
->
{ title : String
, body : List (Html Msg)
}
2020-03-28 04:09:01 +00:00
view model =
let
title =
case model.page of
Packages _ ->
"NixOS Search - Packages"
Options _ ->
"NixOS Search - Options"
_ ->
"NixOS Search"
in
{ title = title
, body =
[ div []
[ header []
[ div [ class "navbar navbar-static-top" ]
[ div [ class "navbar-inner" ]
[ div [ class "container" ]
[ button
[ type_ "button"
, class "btn btn-navbar"
, attribute "data-toggle" "collapse"
, attribute "data-target" ".nav-collapse"
]
[ span [ class "icon-bar" ] []
, span [ class "icon-bar" ] []
, span [ class "icon-bar" ] []
]
, a [ class "brand", href "https://nixos.org" ]
[ img [ src "https://nixos.org/logo/nix-wiki.png", class "logo" ] []
]
, div [ class "nav-collapse collapse" ]
[ ul [ class "nav pull-left" ]
(viewNavigation model.page model.url)
]
]
2020-04-10 08:13:50 +00:00
]
]
]
, div [ class "container main" ]
[ div [ id "content" ] [ viewPage model ]
, footer
[ class "container text-center" ]
[ div []
[ span [] [ text "Elasticsearch instance graciously provided by " ]
, a [ href "https://bonsai.io" ] [ text "Bonsai" ]
, span [] [ text "." ]
]
, div []
[ span [] [ text " Thank you " ]
]
]
]
2020-03-28 04:09:01 +00:00
]
]
}
2020-03-28 04:09:01 +00:00
viewNavigation : Page -> Url.Url -> List (Html Msg)
viewNavigation page url =
let
preserveSearchOptions =
case page of
Packages model ->
model.query
|> Maybe.map (\q -> [ Url.Builder.string "query" q ])
|> Maybe.withDefault []
|> List.append [ Url.Builder.string "channel" model.channel ]
Options model ->
model.query
|> Maybe.map (\q -> [ Url.Builder.string "query" q ])
|> Maybe.withDefault []
|> List.append [ Url.Builder.string "channel" model.channel ]
_ ->
[]
createUrl path =
[]
|> List.append preserveSearchOptions
|> Url.Builder.absolute [ path ]
in
List.map
(viewNavigationItem url)
[ ( "https://nixos.org", "Back to nixos.org" )
, ( createUrl "packages", "Packages" )
, ( createUrl "options", "Options" )
]
viewNavigationItem :
Url.Url
-> ( String, String )
-> Html Msg
viewNavigationItem url ( path, title ) =
li
[ classList
[ ( "active"
, String.startsWith url.path path
)
]
]
[ a [ href path ] [ text title ] ]
2020-04-10 09:04:03 +00:00
viewPage : Model -> Html Msg
viewPage model =
case model.page of
NotFound ->
div [] [ text "Not Found" ]
2020-03-28 04:09:01 +00:00
Home _ ->
div [] [ text "Welcome" ]
2020-03-28 04:09:01 +00:00
Packages packagesModel ->
Html.map (\m -> PackagesMsg m) <| Page.Packages.view packagesModel
2020-04-10 08:13:50 +00:00
Options optionsModel ->
Html.map (\m -> OptionsMsg m) <| Page.Options.view optionsModel
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none
2020-03-28 04:09:01 +00:00
-- MAIN
main : Program Flags Model Msg
2020-03-28 04:09:01 +00:00
main =
Browser.application
{ init = init
, onUrlRequest = ClickedLink
, onUrlChange = ChangedUrl
, subscriptions = subscriptions
2020-03-28 04:09:01 +00:00
, update = update
, view = view
2020-03-28 04:09:01 +00:00
}