Update a ton of things

This commit is contained in:
Richard Feldman
2016-06-24 17:40:54 -07:00
parent 908ca61c77
commit c8e9a117f5
56 changed files with 1023 additions and 1466 deletions

View File

@@ -1,182 +1,126 @@
module ElmHub (..) where
module ElmHub exposing (..)
import Html exposing (..)
import Html.Attributes exposing (class, target, href, property)
import Html.Attributes exposing (class, target, href, property, defaultValue)
import Html.Events exposing (..)
import Http
import Auth
import Task exposing (Task)
import Effects exposing (Effects)
import Json.Decode exposing (Decoder, (:=))
import Json.Decode exposing (Decoder)
import Json.Decode.Pipeline exposing (..)
import Json.Encode
import Signal exposing (Address)
import Dict exposing (Dict)
searchFeed : Address String -> String -> Effects Action
searchFeed address query =
let
getQueryUrl : String -> String
getQueryUrl query =
-- See https://developer.github.com/v3/search/#example for how to customize!
url =
"https://api.github.com/search/repositories?access_token="
"https://api.github.com/search/repositories?access_token="
++ Auth.token
++ "&q="
++ query
++ "+language:elm&sort=stars&order=desc"
-- These only talk to JavaScript ports now. They never result in Actions
-- actually do any actions themselves.
task =
performAction
(\_ -> DoNothing)
(\_ -> DoNothing)
(Signal.send address query)
in
Effects.task task
responseDecoder : Decoder (List SearchResult)
responseDecoder =
"items" := Json.Decode.list searchResultDecoder
Json.Decode.at [ "items" ] (Json.Decode.list searchResultDecoder)
searchResultDecoder : Decoder SearchResult
searchResultDecoder =
decode SearchResult
|> required "id" Json.Decode.int
|> required "full_name" Json.Decode.string
|> required "stargazers_count" Json.Decode.int
{-| Note: this will be a standard function in the next release of Elm.
Example:
type Action =
HandleResponse String | HandleError Http.Error
performAction
(\responseString -> HandleResponse responseString)
(\httpError -> HandleError httpError)
(Http.getString "https://google.com?q=something")
-}
performAction : (a -> b) -> (y -> b) -> Task y a -> Task x b
performAction successToAction errorToAction task =
let
successTask =
Task.map successToAction task
in
Task.onError successTask (\err -> Task.succeed (errorToAction err))
decode SearchResult
|> required "id" Json.Decode.int
|> required "full_name" Json.Decode.string
|> required "stargazers_count" Json.Decode.int
type alias Model =
{ query : String
, results : Dict ResultId SearchResult
, errorMessage : Maybe String
}
{ query : String
, results : Dict ResultId SearchResult
, errorMessage : Maybe String
}
type alias SearchResult =
{ id : ResultId
, name : String
, stars : Int
}
{ id : ResultId
, name : String
, stars : Int
}
type alias ResultId =
Int
Int
initialModel : Model
initialModel =
{ query = "tutorial"
, results = Dict.empty
, errorMessage = Nothing
}
{ query = "tutorial"
, results = Dict.empty
, errorMessage = Nothing
}
view : Address Action -> Model -> Html
view address model =
div
[ class "content" ]
[ header
[]
[ h1 [] [ text "ElmHub" ]
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
view : Model -> Html Msg
view model =
div [ class "content" ]
[ header []
[ h1 [] [ text "ElmHub" ]
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
]
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
, button [ class "search-button", onClick Search ] [ text "Search" ]
, ul [ class "results" ] (viewSearchResults model.results)
]
, input [ class "search-query", onInput address SetQuery, defaultValue model.query ] []
, button [ class "search-button", onClick address Search ] [ text "Search" ]
, ul
[ class "results" ]
(viewSearchResults address model.results)
]
viewSearchResults : Address Action -> Dict ResultId SearchResult -> List Html
viewSearchResults address results =
-- TODO sort by star count and render
[]
onInput address wrap =
on "input" targetValue (\val -> Signal.message address (wrap val))
defaultValue str =
property "defaultValue" (Json.Encode.string str)
viewSearchResult : Address Action -> SearchResult -> Html
viewSearchResult address result =
li
viewSearchResults : Dict ResultId SearchResult -> List (Html Msg)
viewSearchResults results =
-- TODO sort by star count and render
[]
[ span [ class "star-count" ] [ text (toString result.stars) ]
, a
[ href ("https://github.com/" ++ result.name), target "_blank" ]
[ text result.name ]
, button
[ class "hide-result", onClick address (DeleteById result.id) ]
[ text "X" ]
]
type Action
= Search
| SetQuery String
| DeleteById ResultId
| SetResults (List SearchResult)
| SetErrorMessage (Maybe String)
| DoNothing
viewSearchResult : SearchResult -> Html Msg
viewSearchResult result =
li []
[ span [ class "star-count" ] [ text (toString result.stars) ]
, a [ href ("https://github.com/" ++ result.name), target "_blank" ]
[ text result.name ]
, button [ class "hide-result", onClick (DeleteById result.id) ]
[ text "X" ]
]
update : Address String -> Action -> Model -> ( Model, Effects Action )
update searchAddress action model =
case action of
Search ->
( model, searchFeed searchAddress model.query )
type Msg
= Search
| SetQuery String
| DeleteById ResultId
| SetResults (List SearchResult)
| SetErrorMessage (Maybe String)
| DoNothing
SetQuery query ->
( { model | query = query }, Effects.none )
SetResults results ->
let
resultsById : Dict ResultId SearchResult
resultsById =
-- TODO convert results list into a Dict
Dict.empty
in
( { model | results = resultsById }, Effects.none )
update : (String -> Cmd Msg) -> Msg -> Model -> ( Model, Cmd Msg )
update searchFeed msg model =
case msg of
Search ->
( model, searchFeed (getQueryUrl model.query) )
DeleteById id ->
-- TODO delete the result with the given id
( model, Effects.none )
SetQuery query ->
( { model | query = query }, Cmd.none )
SetErrorMessage errorMessage ->
( { model | errorMessage = errorMessage }, Effects.none )
SetResults results ->
let
resultsById : Dict ResultId SearchResult
resultsById =
-- TODO convert results list into a Dict
Dict.empty
in
( { model | results = resultsById }, Cmd.none )
DoNothing ->
( model, Effects.none )
DeleteById id ->
-- TODO delete the result with the given id
( model, Cmd.none )
SetErrorMessage errorMessage ->
( { model | errorMessage = errorMessage }, Cmd.none )
DoNothing ->
( model, Cmd.none )

View File

@@ -1,58 +1,31 @@
module Main (..) where
port module Main exposing (..)
import StartApp
import ElmHub exposing (..)
import Effects exposing (Effects)
import Task exposing (Task)
import Html exposing (Html)
import Signal
import Json.Encode
import Json.Decode
import Html.App
import Json.Decode exposing (Value)
main : Signal Html
main : Program Never
main =
app.html
Html.App.program
{ view = view
, update = update githubSearch
, init = ( initialModel, githubSearch (getQueryUrl initialModel.query) )
, subscriptions = \_ -> githubResponse decodeResponse
}
app : StartApp.App Model
app =
StartApp.start
{ view = view
, update = update search.address
, init = ( initialModel, searchFeed search.address initialModel.query )
, inputs = [ responseActions ]
}
decodeResponse : Json.Decode.Value -> Msg
decodeResponse json =
case Json.Decode.decodeValue responseDecoder json of
Err err ->
SetErrorMessage (Just err)
Ok results ->
SetResults results
port tasks : Signal (Task Effects.Never ())
port tasks =
app.tasks
port githubSearch : String -> Cmd msg
search : Signal.Mailbox String
search =
Signal.mailbox ""
port githubSearch : Signal String
port githubSearch =
search.signal
responseActions : Signal Action
responseActions =
Signal.map decodeGithubResponse githubResponse
decodeGithubResponse : Json.Encode.Value -> Action
decodeGithubResponse value =
case Json.Decode.decodeValue responseDecoder value of
Ok results ->
SetResults results
Err message ->
SetErrorMessage (Just message)
port githubResponse : Signal Json.Encode.Value
port githubResponse : (Json.Decode.Value -> msg) -> Sub msg

View File

@@ -4,14 +4,14 @@ Part 9
## Installation
```bash
elm package install
elm-package install
```
(Answer `y` at the prompt. In rare cases a known issue can cause the download
to fail; in that case, just run `elm package install` again.)
to fail; in that case, just run `elm-package install` again.)
## Building
```bash
elm live Main.elm --open -- --output=elm.js
elm-live Main.elm --open -- --output=elm.js
```

View File

@@ -10,11 +10,9 @@
"exposed-modules": [],
"dependencies": {
"NoRedInk/elm-decode-pipeline": "1.0.0 <= v < 2.0.0",
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.0 <= v < 3.0.0",
"evancz/elm-html": "4.0.0 <= v < 5.0.0",
"evancz/elm-http": "3.0.0 <= v < 4.0.0",
"evancz/start-app": "2.0.0 <= v < 3.0.0"
"elm-lang/core": "4.0.1 <= v < 5.0.0",
"elm-lang/html": "1.0.0 <= v < 2.0.0",
"evancz/elm-http": "3.0.1 <= v < 4.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
}
"elm-version": "0.17.0 <= v < 0.18.0"
}