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

361 lines
9.2 KiB
Elm
Raw Normal View History

2021-04-19 23:31:11 +00:00
module Pages.App_String exposing (Model, Msg, Params, page)
2021-05-04 16:27:42 +00:00
import Html exposing (Html, a, button, div, h2, h5, i, img, li, p, span, text, ul)
import Html.Attributes exposing (alt, class, href, src, style)
2021-04-19 23:31:11 +00:00
import Html.Events exposing (onClick)
import Http
import Json.Decode as Decode
import Json.Decode.Extra as Decode exposing (andMap)
2021-05-04 16:27:42 +00:00
import Markdown
import Regex
2021-04-19 23:31:11 +00:00
import Spa.Document exposing (Document)
import Spa.Generated.Route as Route
2021-04-19 23:31:11 +00:00
import Spa.Page as Page exposing (Page)
import Spa.Url as Url exposing (Url)
2021-05-04 16:27:42 +00:00
2021-04-19 23:50:06 +00:00
-- INIT
2021-04-19 23:31:11 +00:00
page : Page Params Model Msg
page =
Page.element
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}
2021-05-04 16:27:42 +00:00
2021-04-19 23:31:11 +00:00
type alias Params =
2021-05-04 16:27:42 +00:00
{ app : String
}
2021-04-19 23:31:11 +00:00
type alias App =
{ name : String
, category : String
, repository : Maybe String
2023-03-27 15:51:30 +00:00
, versions : List String
2021-04-19 23:31:11 +00:00
, icon : Maybe String
2023-03-26 22:47:47 +00:00
, status : Int
, slug : String
, default_branch : String
, website : Maybe String
, description : Maybe String
2021-04-19 23:31:11 +00:00
}
2021-05-04 16:27:42 +00:00
type alias Model =
2021-04-19 23:31:11 +00:00
{ 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 = "" }, loadApp )
2021-04-19 23:31:11 +00:00
default_image : String
2021-05-04 16:27:42 +00:00
2021-04-19 23:50:06 +00:00
-- FIXME: change to absolute URL, if this works?
2021-05-04 16:27:42 +00:00
default_image =
"/logo.png"
2021-04-19 23:31:11 +00:00
-- 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 }, loadApp )
2021-04-19 23:31:11 +00:00
GotApps result ->
case result of
Ok apps ->
2021-05-04 16:27:42 +00:00
let
-- TODO better way of getting a single app?
apps_filtered =
List.filter (\app -> app.slug == model.url.params.app) apps
in
case List.head apps_filtered of
Nothing ->
( { model | status = Failure }, Cmd.none )
Just item ->
( { model | status = Success item }, loadREADME item )
2021-04-19 23:31:11 +00:00
2021-04-25 14:00:04 +00:00
Err _ ->
2021-05-04 16:27:42 +00:00
( { model | status = Failure }, Cmd.none )
2021-04-19 23:31:11 +00:00
GotText result ->
case result of
Ok content ->
2021-04-19 23:50:06 +00:00
-- update model.content with the loaded README
let
-- remove HTML comments
2021-05-04 16:27:42 +00:00
pattern =
"<!--.*-->"
maybeRegex =
Regex.fromString pattern
regex =
Maybe.withDefault Regex.never maybeRegex
2021-04-19 23:50:06 +00:00
in
2021-05-04 16:27:42 +00:00
( { model | readme = Regex.replace regex (\_ -> "") content }, Cmd.none )
2021-04-19 23:31:11 +00:00
2021-04-25 14:00:04 +00:00
Err _ ->
2021-05-04 16:27:42 +00:00
( { model | status = Failure }, Cmd.none )
2021-04-19 23:31:11 +00:00
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
-- VIEW
view : Model -> Document Msg
view model =
2021-04-23 17:06:06 +00:00
{ title = title model
2021-04-19 23:31:11 +00:00
, body = [ body model ]
}
2021-04-23 17:06:06 +00:00
title : Model -> String
title model =
case model.status of
Loading ->
2022-05-04 09:19:28 +00:00
"loading Co-op Cloud Recipes"
2021-05-04 16:27:42 +00:00
2021-04-23 17:06:06 +00:00
Failure ->
2022-05-04 09:19:28 +00:00
"error - Co-op Cloud Recipes"
2021-05-04 16:27:42 +00:00
2021-04-23 17:06:06 +00:00
Success app ->
2022-05-04 09:19:28 +00:00
app.name ++ " Co-op Cloud Recipes"
2021-04-23 17:06:06 +00:00
2021-04-19 23:31:11 +00:00
body : Model -> Html Msg
body model =
div [ class "pt-3" ]
[ case model.status of
Failure ->
2021-04-24 13:36:56 +00:00
div []
[ div [ class "alert alert-danger" ]
[ p [] [ text "Unable to load app data" ]
, button [ class "btn btn-danger", onClick MorePlease ] [ text "Try Again!" ]
]
2021-04-19 23:31:11 +00:00
]
Loading ->
2021-05-04 16:27:42 +00:00
div [ class "d-flex align-items-center", style "height" "89vh" ]
[ div [ class "spinner-border m-auto text-light" ]
[ span [ class "sr-only" ] [ text "Loading..." ]
]
]
2021-04-19 23:31:11 +00:00
Success app ->
div []
[ div [ class "row" ]
2021-05-04 16:27:42 +00:00
[ viewApp app model.readme ]
2021-04-19 23:31:11 +00:00
]
]
2021-05-04 16:27:42 +00:00
2021-04-19 23:31:11 +00:00
viewStatusBadge : App -> Html Msg
viewStatusBadge app =
let
status_class =
case app.status of
2023-03-26 22:47:47 +00:00
5 ->
2021-04-19 23:31:11 +00:00
"badge-success"
2021-05-04 16:27:42 +00:00
2023-03-26 22:47:47 +00:00
4 ->
2021-04-19 23:31:11 +00:00
"badge-info"
2021-05-04 16:27:42 +00:00
2023-03-26 22:47:47 +00:00
3 ->
2021-04-19 23:31:11 +00:00
"badge-warning"
2021-05-04 16:27:42 +00:00
2023-03-26 22:47:47 +00:00
2 ->
2021-04-19 23:31:11 +00:00
"badge-danger"
2021-05-04 16:27:42 +00:00
2021-04-19 23:31:11 +00:00
_ ->
"badge-dark"
in
2021-05-04 16:27:42 +00:00
span [ class ("card-link badge " ++ status_class) ]
2023-03-26 22:47:47 +00:00
[ text ("Score: " ++ String.fromInt app.status) ]
2021-05-04 16:27:42 +00:00
2021-04-19 23:31:11 +00:00
viewApp : App -> String -> Html Msg
viewApp app readme =
let
icon_url =
case app.icon of
Just "" ->
default_image
2021-05-04 16:27:42 +00:00
2021-04-19 23:31:11 +00:00
Just i ->
i
2021-05-04 16:27:42 +00:00
2021-04-19 23:31:11 +00:00
Nothing ->
default_image
2021-05-04 16:27:42 +00:00
repository_link =
2021-04-19 23:31:11 +00:00
case app.repository of
2021-04-23 17:06:06 +00:00
Just link ->
2021-05-04 16:27:42 +00:00
a [ class "card-link", href link ]
[ i [ class "fab fa-git-alt" ] []
, text "code"
]
2021-04-19 23:31:11 +00:00
Nothing ->
text ""
2021-05-04 16:27:42 +00:00
website_link =
case app.website of
Just link ->
case link of
"" ->
text ""
2021-05-04 16:27:42 +00:00
_ ->
2021-05-04 16:27:42 +00:00
a [ class "card-link", href link ]
[ i [ class "fas fa-home" ] []
, text "homepage"
]
Nothing ->
text ""
2021-05-04 16:27:42 +00:00
in
div [ class "col-md-6 col-sm-10 mb-3 offset-md-3 offset-sm-1" ]
[ div [ class "card" ]
[ div [ class "card-header" ]
[ a
[ class "btn btn-sm border border-secondary card-link"
, href (Route.toString Route.Top)
2021-04-19 23:31:11 +00:00
]
2021-05-04 16:27:42 +00:00
[ text " back" ]
, span [ class "card-link badge badge-secondary" ] [ text app.category ]
, viewStatusBadge app
, repository_link
, website_link
]
, img [ class "card-img-top card-img-large", src icon_url, alt ("icon for " ++ app.name) ] []
2021-05-04 16:27:42 +00:00
, div [ class "card-body" ]
-- render Markdown with no special options
[ div [] (Markdown.toHtml Nothing readme)
2021-04-19 23:31:11 +00:00
]
2021-05-04 16:27:42 +00:00
, div [ class "card-footer" ]
[ h5 [] [ text "Versions" ]
, ul [] (
List.map (\version -> li [] [ text (version) ]) app.versions
)]
2021-04-19 23:31:11 +00:00
]
2021-05-04 16:27:42 +00:00
]
2021-04-19 23:31:11 +00:00
-- HTTP
loadApp : Cmd Msg
loadApp =
2021-05-04 16:27:42 +00:00
Http.get
2022-05-04 09:30:54 +00:00
{ url = "https://recipes.coopcloud.tech/recipes.json"
2021-05-04 16:27:42 +00:00
, expect = Http.expectJson GotApps appListDecoder
}
loadREADME : App -> Cmd Msg
2021-05-04 16:27:42 +00:00
loadREADME app =
let
2021-05-04 16:27:42 +00:00
repository_link =
case app.repository of
Just link ->
2021-05-04 16:27:42 +00:00
a [ class "card-link", href link ]
[ i [ class "fab fa-git-alt" ] []
, text "code"
]
Nothing ->
text ""
in
2021-05-04 16:27:42 +00:00
Http.get
-- FIXME use live Gitea link
2023-01-09 03:04:39 +00:00
{ url = "https://git.coopcloud.tech/coop-cloud/" ++ app.slug ++ "/raw/branch/" ++ app.default_branch ++ "/README.md"
2021-05-04 16:27:42 +00:00
, expect = Http.expectString GotText
}
2021-04-19 23:31:11 +00:00
featuresDecoder =
2021-05-04 16:27:42 +00:00
Decode.oneOf
2023-03-26 22:47:47 +00:00
[ Decode.at [ "status" ] Decode.int
, Decode.succeed 5
2021-04-19 23:31:11 +00:00
]
versionsDecoder : Decode.Decoder (List String)
2023-03-27 15:51:30 +00:00
versionsDecoder =
Decode.list (Decode.keyValuePairs Decode.value)
|> Decode.map buildVersions
2023-03-27 15:51:30 +00:00
buildVersions : List (List ( String, Decode.Value )) -> List String
2023-03-27 15:51:30 +00:00
buildVersions versions =
List.concatMap (List.map (\( version, _ ) -> version)) versions
2023-03-27 15:51:30 +00:00
2021-04-19 23:31:11 +00:00
appDecoder : Decode.Decoder App
appDecoder =
Decode.succeed App
|> andMap (Decode.field "name" Decode.string)
|> andMap (Decode.field "category" Decode.string)
|> andMap (Decode.maybe (Decode.field "repository" Decode.string))
2023-03-27 15:51:30 +00:00
|> andMap (Decode.at [ "versions" ] versionsDecoder)
-- |> andMap (Decode.succeed Nothing)
|> andMap (Decode.maybe (Decode.field "icon" Decode.string))
|> andMap (Decode.at [ "features" ] featuresDecoder)
2021-04-25 13:25:25 +00:00
|> andMap (Decode.succeed "")
|> andMap (Decode.field "default_branch" Decode.string)
|> andMap (Decode.maybe (Decode.field "website" Decode.string))
|> andMap (Decode.maybe (Decode.field "description" Decode.string))
2021-04-19 23:31:11 +00:00
appListDecoder : Decode.Decoder (List App)
appListDecoder =
2021-04-25 13:25:25 +00:00
Decode.keyValuePairs appDecoder
|> Decode.map buildApp
2021-05-04 16:27:42 +00:00
buildApp : List ( String, App ) -> List App
2021-04-25 13:25:25 +00:00
buildApp apps =
2021-05-04 16:27:42 +00:00
List.map (\( slug, app ) -> { app | slug = slug }) apps