start implementing models for Mi API integration
This commit is contained in:
parent
a3d722e2ed
commit
b06a90ccc5
|
@ -1,2 +1,3 @@
|
||||||
index.html
|
index.html
|
||||||
|
index.js
|
||||||
elm-stuff
|
elm-stuff
|
|
@ -11,14 +11,14 @@
|
||||||
"elm/html": "1.0.0",
|
"elm/html": "1.0.0",
|
||||||
"elm/http": "2.0.0",
|
"elm/http": "2.0.0",
|
||||||
"elm/json": "1.1.3",
|
"elm/json": "1.1.3",
|
||||||
|
"elm/time": "1.0.0",
|
||||||
|
"elm/url": "1.0.0",
|
||||||
"rtfeldman/elm-iso8601-date-strings": "1.1.3"
|
"rtfeldman/elm-iso8601-date-strings": "1.1.3"
|
||||||
},
|
},
|
||||||
"indirect": {
|
"indirect": {
|
||||||
"elm/bytes": "1.0.8",
|
"elm/bytes": "1.0.8",
|
||||||
"elm/file": "1.0.5",
|
"elm/file": "1.0.5",
|
||||||
"elm/parser": "1.1.0",
|
"elm/parser": "1.1.0",
|
||||||
"elm/time": "1.0.0",
|
|
||||||
"elm/url": "1.0.0",
|
|
||||||
"elm/virtual-dom": "1.0.2"
|
"elm/virtual-dom": "1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,7 +1,79 @@
|
||||||
module Main exposing (main)
|
module Main exposing (main)
|
||||||
|
|
||||||
import Html exposing (Html, text)
|
import Browser exposing (sandbox)
|
||||||
|
import Html exposing (Html, button, div, ul, li, span, input, text)
|
||||||
|
import Html.Attributes exposing (autofocus, class, value)
|
||||||
|
import Html.Events exposing (onClick, onInput)
|
||||||
|
import Mi
|
||||||
|
import Mi.Switch
|
||||||
|
|
||||||
main : Html msg
|
|
||||||
|
-- We added a new AddTodo message type.
|
||||||
|
|
||||||
|
|
||||||
|
type Msg
|
||||||
|
= UpdateText String
|
||||||
|
| AddTodo
|
||||||
|
| RemoveTodo Int
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- We added a new property called todos, which is a list of strings.
|
||||||
|
|
||||||
|
|
||||||
|
type alias Model =
|
||||||
|
{ text : String
|
||||||
|
, todos : List String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- We added (autofocus True), which is like the native HTML autofocus attribute.
|
||||||
|
-- We also added a button that triggers an onClick event when clicked which
|
||||||
|
-- passes an AddTodo message to the update function.
|
||||||
|
|
||||||
|
|
||||||
|
view : Model -> Html Msg
|
||||||
|
view model =
|
||||||
|
div [ class "text-center" ]
|
||||||
|
[ input [ onInput UpdateText, value model.text, autofocus True ] []
|
||||||
|
, button [ onClick AddTodo, class "btn btn-primary" ] [ text "Add Todo" ]
|
||||||
|
, ul [] (List.indexedMap (\index todo -> li [] [ text todo, span [onClick (RemoveTodo index)] [text " X"] ]) model.todos)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
update : Msg -> Model -> Model
|
||||||
|
update msg model =
|
||||||
|
case msg of
|
||||||
|
UpdateText newText ->
|
||||||
|
{ model | text = newText }
|
||||||
|
|
||||||
|
-- We append the model.text value to the end of our list of todo strings.
|
||||||
|
AddTodo ->
|
||||||
|
{ model | text = "", todos = model.todos ++ [ model.text ] }
|
||||||
|
|
||||||
|
RemoveTodo index ->
|
||||||
|
let
|
||||||
|
beforeTodos =
|
||||||
|
List.take index model.todos
|
||||||
|
|
||||||
|
afterTodos =
|
||||||
|
List.drop (index + 1) model.todos
|
||||||
|
|
||||||
|
newTodos =
|
||||||
|
beforeTodos ++ afterTodos
|
||||||
|
in
|
||||||
|
{ model | todos = newTodos }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- We set the todos property so that it's initially an empty list.
|
||||||
|
|
||||||
|
|
||||||
|
main : Program () Model Msg
|
||||||
main =
|
main =
|
||||||
text "Hello, World!"
|
sandbox
|
||||||
|
{ init = { text = "", todos = [] }
|
||||||
|
, view = view
|
||||||
|
, update = update
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
module Mi exposing (TokenData, errorToString, expectJson, request, tokenDecoder)
|
||||||
|
|
||||||
|
import Http exposing (Error(..))
|
||||||
|
import Json.Decode as D
|
||||||
|
|
||||||
|
|
||||||
|
type alias TokenData =
|
||||||
|
{ sub : String
|
||||||
|
, jti : String, aud: String, iss: String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tokenDecoder : D.Decoder TokenData
|
||||||
|
tokenDecoder =
|
||||||
|
D.map4 TokenData
|
||||||
|
(D.field "sub" D.string)
|
||||||
|
(D.field "jti" D.string)
|
||||||
|
(D.field "aud" D.string)
|
||||||
|
(D.field "iss" D.string)
|
||||||
|
|
||||||
|
|
||||||
|
request method token path body expect =
|
||||||
|
Http.request
|
||||||
|
{ method = method
|
||||||
|
, body = body
|
||||||
|
, headers =
|
||||||
|
[ Http.header "Authorization" token
|
||||||
|
]
|
||||||
|
, url = path
|
||||||
|
, expect = expect
|
||||||
|
, timeout = Nothing
|
||||||
|
, tracker = Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
expectJson : (Result Http.Error a -> msg) -> D.Decoder a -> Http.Expect msg
|
||||||
|
expectJson toMsg decoder =
|
||||||
|
Http.expectStringResponse toMsg <|
|
||||||
|
\response ->
|
||||||
|
case response of
|
||||||
|
Http.BadUrl_ url ->
|
||||||
|
Err (Http.BadUrl url)
|
||||||
|
|
||||||
|
Http.Timeout_ ->
|
||||||
|
Err Http.Timeout
|
||||||
|
|
||||||
|
Http.NetworkError_ ->
|
||||||
|
Err Http.NetworkError
|
||||||
|
|
||||||
|
Http.BadStatus_ metadata body ->
|
||||||
|
Err (Http.BadStatus metadata.statusCode)
|
||||||
|
|
||||||
|
Http.GoodStatus_ metadata body ->
|
||||||
|
case D.decodeString decoder body of
|
||||||
|
Ok value ->
|
||||||
|
Ok value
|
||||||
|
|
||||||
|
Err err ->
|
||||||
|
Err (Http.BadBody (D.errorToString err))
|
||||||
|
|
||||||
|
|
||||||
|
errorToString : Http.Error -> String
|
||||||
|
errorToString err =
|
||||||
|
case err of
|
||||||
|
Timeout ->
|
||||||
|
"Timeout exceeded"
|
||||||
|
|
||||||
|
NetworkError ->
|
||||||
|
"Network error"
|
||||||
|
|
||||||
|
BadStatus st ->
|
||||||
|
"Bad status code: " ++ String.fromInt st
|
||||||
|
|
||||||
|
BadBody text ->
|
||||||
|
"Unexpected response from api: " ++ text
|
||||||
|
|
||||||
|
BadUrl url ->
|
||||||
|
"Malformed url: " ++ url
|
|
@ -0,0 +1,56 @@
|
||||||
|
module Mi.Switch exposing (..)
|
||||||
|
|
||||||
|
import Html exposing (..)
|
||||||
|
import Html.Attributes exposing (..)
|
||||||
|
import Iso8601
|
||||||
|
import Json.Decode exposing (Decoder, field, int, map5, nullable, string)
|
||||||
|
import Time exposing (..)
|
||||||
|
import Url.Builder as UB
|
||||||
|
|
||||||
|
type alias Switch =
|
||||||
|
{ id : String
|
||||||
|
, who : String
|
||||||
|
, started_at : Posix
|
||||||
|
, ended_at : Maybe Posix
|
||||||
|
, duration : Maybe Int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
decoder : Decoder Switch
|
||||||
|
decoder =
|
||||||
|
map5 Switch
|
||||||
|
(field "id" string)
|
||||||
|
(field "who" string)
|
||||||
|
(field "started_at" Iso8601.decoder)
|
||||||
|
(field "ended_at" (nullable Iso8601.decoder))
|
||||||
|
(field "duration" (nullable int))
|
||||||
|
|
||||||
|
|
||||||
|
switchURL : String
|
||||||
|
switchURL =
|
||||||
|
UB.absolute
|
||||||
|
[ "api", "switches", "switch" ]
|
||||||
|
[]
|
||||||
|
|
||||||
|
|
||||||
|
idURL : String -> String
|
||||||
|
idURL id =
|
||||||
|
UB.absolute
|
||||||
|
[ "api","switches", "id", id ]
|
||||||
|
[]
|
||||||
|
|
||||||
|
|
||||||
|
frontURL : String
|
||||||
|
frontURL =
|
||||||
|
UB.absolute
|
||||||
|
["api", "switches", "current" ]
|
||||||
|
[]
|
||||||
|
|
||||||
|
|
||||||
|
listURL : Int -> Int -> String
|
||||||
|
listURL limit page =
|
||||||
|
UB.absolute
|
||||||
|
["api", "switches", "" ]
|
||||||
|
[ UB.int "limit" limit
|
||||||
|
, UB.int "page" page
|
||||||
|
]
|
|
@ -1,4 +1,16 @@
|
||||||
{
|
{
|
||||||
|
"gruvbox-css": {
|
||||||
|
"branch": "master",
|
||||||
|
"description": "My minimal Gruvbox CSS file I've been keeping multiple places",
|
||||||
|
"homepage": null,
|
||||||
|
"owner": "Xe",
|
||||||
|
"repo": "gruvbox-css",
|
||||||
|
"rev": "6e1841c94190a1e06e63a2596767e66c35671320",
|
||||||
|
"sha256": "0s7whnin63558i70wp3by3rydsdx0qdzh5553km1s29w81npmgj6",
|
||||||
|
"type": "tarball",
|
||||||
|
"url": "https://github.com/Xe/gruvbox-css/archive/6e1841c94190a1e06e63a2596767e66c35671320.tar.gz",
|
||||||
|
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
|
||||||
|
},
|
||||||
"naersk": {
|
"naersk": {
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"description": "Build rust crates in Nix. No configuration, no code generation, no IFD. Sandbox friendly.",
|
"description": "Build rust crates in Nix. No configuration, no code generation, no IFD. Sandbox friendly.",
|
||||||
|
|
Loading…
Reference in New Issue