recipes.coopcloud.tech/src/Pages/App_String.elm

245 lines
6.5 KiB
Elm

module Pages.App_String exposing (Model, Msg, Params, page)
import Regex
import Html exposing (Html, button, div, h2, h5, img, text, ul, li, a, p, span)
import Html.Attributes exposing (src, style, class, alt, href)
import Html.Events exposing (onClick)
import Http
import Markdown
import Json.Decode as Decode
import Spa.Document exposing (Document)
import Spa.Page as Page exposing (Page)
import Spa.Url as Url exposing (Url)
-- INIT
page : Page Params Model Msg
page =
Page.element
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}
type alias Params =
{ app : String
}
type alias App =
{ name : String
, category : String
, repository : Maybe String
, versions : Maybe (List String)
, icon : Maybe String
, status : String
}
type alias Model =
{ url : Url Params
, status : Status
, readme : String
}
type Status
= Failure
| Loading
| Success App
init : Url Params -> ( Model, Cmd Msg )
init url =
( { url = url, status = Loading, readme = "" }, loadData )
default_image : String
-- FIXME: change to absolute URL, if this works?
default_image = "http://localhost:8000/logo.png"
-- UPDATE
type Msg
= MorePlease
| GotApps (Result Http.Error (List App))
| GotText (Result Http.Error String)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
MorePlease ->
( { model | status = Loading }, loadData )
GotApps result ->
case result of
Ok apps ->
let
-- TODO better way of getting a single app?
apps_filtered = List.filter (\app -> app.name == model.url.params.app) apps
in
case List.head apps_filtered of
Nothing ->
( { model | status = Failure }, Cmd.none )
Just item ->
( { model | status = Success (item) }, Cmd.none )
Err _ ->
( { model | status = Failure }, Cmd.none )
GotText result ->
case result of
Ok content ->
-- update model.content with the loaded README
let
-- remove HTML comments
pattern = "<!--.*-->"
maybeRegex = Regex.fromString pattern
regex = Maybe.withDefault Regex.never maybeRegex
in
( { model | readme = Regex.replace regex (\_ -> "") content }, Cmd.none )
Err _ ->
( { model | status = Failure }, Cmd.none )
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
-- VIEW
view : Model -> Document Msg
view model =
{ title = "abra app"
, body = [ body model ]
}
body : Model -> Html Msg
body model =
div [ class "pt-3" ]
[ case model.status of
Failure ->
div [ ]
[ text "I could not load a random cat for some reason. "
, button [ onClick MorePlease ] [ text "Try Again!" ]
]
Loading ->
text "Loading..."
Success app ->
div []
[ div [ class "row" ]
[ viewApp app model.readme ]
]
]
viewStatusBadge : App -> Html Msg
viewStatusBadge app =
let
status_class =
case app.status of
"1" ->
"badge-success"
"2" ->
"badge-info"
"3" ->
"badge-warning"
"4" ->
"badge-danger"
_ ->
"badge-dark"
in
span [ class ("card-link badge " ++ status_class) ]
[ text ("Score: " ++ app.status) ]
viewApp : App -> String -> Html Msg
viewApp app readme =
let
icon_url =
case app.icon of
Just "" ->
default_image
Just i ->
i
Nothing ->
default_image
repository_link =
case app.repository of
Just i ->
a [ class "card-link", href i ] [ text "code" ]
Nothing ->
text ""
in
div [ class "col-md-6 col-sm-10 mb-3 offset-md-3 offset-sm-1" ]
[ div [ class "card" ]
[ div [ class "card-header" ]
[ span [ class "card-link badge badge-secondary" ] [ text app.category ]
, viewStatusBadge app
, repository_link
, a [ class "card-link", href "http://example.com" ] [ text "homepage" ]
-- FIXME: add actual homepage link to apps.json and render here
]
, img [ class "card-img-top", src icon_url, alt ("icon for " ++ app.name) ] []
, div [ class "card-body" ]
-- render Markdown with no special options
[ div [] (Markdown.toHtml Nothing readme)
]
, div [ class "card-footer" ]
[]
]
]
-- HTTP
loadData : Cmd Msg
loadData =
-- fetch app JSON and README in parallel
Cmd.batch
[ Http.get
-- FIXME: change to absolute URL, if this works?
{ url = "http://localhost:8000/abra-apps-list.json"
, expect = Http.expectJson GotApps appListDecoder }
, Http.get
-- FIXME add branch name to apps.json, load actual README
{ url = "http://localhost:1234/coop-cloud/adapt_authoring/raw/branch/main/README.md"
, expect = Http.expectString GotText }
]
featuresDecoder =
-- get features.status if it's there
(Decode.oneOf
[ Decode.at [ "status" ] Decode.string
, Decode.succeed ""
]
)
appDecoder : Decode.Decoder App
appDecoder =
Decode.map6
App
(Decode.field "name" Decode.string)
(Decode.field "category" Decode.string)
(Decode.maybe (Decode.field "repository" Decode.string))
(Decode.succeed Nothing)
(Decode.maybe (Decode.field "icon" Decode.string))
(Decode.at [ "features" ] featuresDecoder)
appListDecoder : Decode.Decoder (List App)
appListDecoder =
Decode.list appDecoder