From b06a90ccc5bf1f54b65fa26603695bf4f48ee33a Mon Sep 17 00:00:00 2001 From: Christine Dodrill Date: Wed, 4 Nov 2020 17:16:39 -0500 Subject: [PATCH] start implementing models for Mi API integration --- frontend/.gitignore | 1 + frontend/elm.json | 4 +- frontend/src/Main.elm | 78 ++++++++++++++++++++++++++++++++++++-- frontend/src/Mi.elm | 78 ++++++++++++++++++++++++++++++++++++++ frontend/src/Mi/Switch.elm | 56 +++++++++++++++++++++++++++ nix/sources.json | 12 ++++++ 6 files changed, 224 insertions(+), 5 deletions(-) create mode 100644 frontend/src/Mi.elm create mode 100644 frontend/src/Mi/Switch.elm diff --git a/frontend/.gitignore b/frontend/.gitignore index 4328a20..8cc1f65 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -1,2 +1,3 @@ index.html +index.js elm-stuff \ No newline at end of file diff --git a/frontend/elm.json b/frontend/elm.json index 29858d4..564d82c 100644 --- a/frontend/elm.json +++ b/frontend/elm.json @@ -11,14 +11,14 @@ "elm/html": "1.0.0", "elm/http": "2.0.0", "elm/json": "1.1.3", + "elm/time": "1.0.0", + "elm/url": "1.0.0", "rtfeldman/elm-iso8601-date-strings": "1.1.3" }, "indirect": { "elm/bytes": "1.0.8", "elm/file": "1.0.5", "elm/parser": "1.1.0", - "elm/time": "1.0.0", - "elm/url": "1.0.0", "elm/virtual-dom": "1.0.2" } }, diff --git a/frontend/src/Main.elm b/frontend/src/Main.elm index 8f4839c..486a757 100644 --- a/frontend/src/Main.elm +++ b/frontend/src/Main.elm @@ -1,7 +1,79 @@ 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 = - text "Hello, World!" + sandbox + { init = { text = "", todos = [] } + , view = view + , update = update + } \ No newline at end of file diff --git a/frontend/src/Mi.elm b/frontend/src/Mi.elm new file mode 100644 index 0000000..917935e --- /dev/null +++ b/frontend/src/Mi.elm @@ -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 \ No newline at end of file diff --git a/frontend/src/Mi/Switch.elm b/frontend/src/Mi/Switch.elm new file mode 100644 index 0000000..59cfd8d --- /dev/null +++ b/frontend/src/Mi/Switch.elm @@ -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 + ] \ No newline at end of file diff --git a/nix/sources.json b/nix/sources.json index c449da1..e332667 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -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///archive/.tar.gz" + }, "naersk": { "branch": "master", "description": "Build rust crates in Nix. No configuration, no code generation, no IFD. Sandbox friendly.",