From c43bd5d738bc42e7586814096ce920a5a7b320c5 Mon Sep 17 00:00:00 2001 From: Ryan Haskell-Glatz Date: Thu, 4 Mar 2021 09:00:12 -0600 Subject: [PATCH] update protected page api --- elm.json | 2 +- examples/02-pages/elm.json | 2 +- examples/03-user-auth/elm.json | 2 +- examples/04-demo/elm.json | 2 +- src/ElmSpa/Internals/Page.elm | 486 ++++++++++++++++++++------------- src/cli/src/new/elm.json | 2 +- src/cli/src/templates/page.ts | 46 ++-- 7 files changed, 331 insertions(+), 211 deletions(-) diff --git a/elm.json b/elm.json index 27eec7c..1854f23 100644 --- a/elm.json +++ b/elm.json @@ -3,7 +3,7 @@ "name": "ryannhg/elm-spa", "summary": "Single page apps made easy.", "license": "BSD-3-Clause", - "version": "5.2.0", + "version": "5.3.0", "exposed-modules": [ "ElmSpa.Request", "ElmSpa.Page", diff --git a/examples/02-pages/elm.json b/examples/02-pages/elm.json index 9cf94a9..e694c97 100644 --- a/examples/02-pages/elm.json +++ b/examples/02-pages/elm.json @@ -13,7 +13,7 @@ "elm/html": "1.0.0", "elm/json": "1.1.3", "elm/url": "1.0.0", - "ryannhg/elm-spa": "5.2.0" + "ryannhg/elm-spa": "5.3.0" }, "indirect": { "elm/time": "1.0.0", diff --git a/examples/03-user-auth/elm.json b/examples/03-user-auth/elm.json index 9cf94a9..e694c97 100644 --- a/examples/03-user-auth/elm.json +++ b/examples/03-user-auth/elm.json @@ -13,7 +13,7 @@ "elm/html": "1.0.0", "elm/json": "1.1.3", "elm/url": "1.0.0", - "ryannhg/elm-spa": "5.2.0" + "ryannhg/elm-spa": "5.3.0" }, "indirect": { "elm/time": "1.0.0", diff --git a/examples/04-demo/elm.json b/examples/04-demo/elm.json index 9cf94a9..e694c97 100644 --- a/examples/04-demo/elm.json +++ b/examples/04-demo/elm.json @@ -13,7 +13,7 @@ "elm/html": "1.0.0", "elm/json": "1.1.3", "elm/url": "1.0.0", - "ryannhg/elm-spa": "5.2.0" + "ryannhg/elm-spa": "5.3.0" }, "indirect": { "elm/time": "1.0.0", diff --git a/src/ElmSpa/Internals/Page.elm b/src/ElmSpa/Internals/Page.elm index 5540c01..c6f2f1d 100644 --- a/src/ElmSpa/Internals/Page.elm +++ b/src/ElmSpa/Internals/Page.elm @@ -1,8 +1,8 @@ module ElmSpa.Internals.Page exposing ( Page, static, sandbox, element, advanced - , Protected(..), protected2 + , Protected(..), protected3 , Bundle, bundle - , protected + , protected, protected2 ) {-| @@ -15,7 +15,7 @@ module ElmSpa.Internals.Page exposing # **User Authentication** -@docs Protected, protected2 +@docs Protected, protected3 # For generated code @@ -27,7 +27,7 @@ module ElmSpa.Internals.Page exposing This will be removed before release, included to prevent bumping to 6.0.0 during beta! -@docs protected +@docs protected, protected2 -} @@ -71,15 +71,7 @@ static : } -> Page shared route effect view () msg static none page = - Page - (\_ _ -> - Ok - { init = \_ -> ( (), none ) - , update = \_ _ -> ( (), none ) - , view = \_ -> page.view - , subscriptions = \_ -> Sub.none - } - ) + Page (\_ _ -> Ok (adapters.static none page)) {-| A page that can keep track of application state. @@ -110,15 +102,7 @@ sandbox : } -> Page shared route effect view model msg sandbox none page = - Page - (\_ _ -> - Ok - { init = \_ -> ( page.init, none ) - , update = \msg model -> ( page.update msg model, none ) - , view = page.view - , subscriptions = \_ -> Sub.none - } - ) + Page (\_ _ -> Ok (adapters.sandbox none page)) {-| A page that can handle effects like [HTTP requests or subscriptions](https://guide.elm-lang.org/effects/). @@ -152,15 +136,7 @@ element : } -> Page shared route effect view model msg element fromCmd page = - Page - (\_ _ -> - Ok - { init = \_ -> page.init |> Tuple.mapSecond fromCmd - , update = \msg model -> page.update msg model |> Tuple.mapSecond fromCmd - , view = page.view - , subscriptions = page.subscriptions - } - ) + Page (\_ _ -> Ok (adapters.element fromCmd page)) {-| A page that can handles **custom** effects like sending a `Shared.Msg` or other general user-defined effects. @@ -191,101 +167,7 @@ advanced : } -> Page shared route effect view model msg advanced page = - Page - (\_ _ -> - Ok - { init = always page.init - , update = page.update - , view = page.view - , subscriptions = page.subscriptions - } - ) - - -{-| Deprecated! Will be replaced by [protected2](#protected2) --} -protected : - { effectNone : effect - , fromCmd : Cmd msg -> effect - , user : shared -> Request route () -> Maybe user - , route : route - } - -> - { static : - { view : user -> view - } - -> Page shared route effect view () msg - , sandbox : - { init : user -> model - , update : user -> msg -> model -> model - , view : user -> model -> view - } - -> Page shared route effect view model msg - , element : - { init : user -> ( model, Cmd msg ) - , update : user -> msg -> model -> ( model, Cmd msg ) - , view : user -> model -> view - , subscriptions : user -> model -> Sub msg - } - -> Page shared route effect view model msg - , advanced : - { init : user -> ( model, effect ) - , update : user -> msg -> model -> ( model, effect ) - , view : user -> model -> view - , subscriptions : user -> model -> Sub msg - } - -> Page shared route effect view model msg - } -protected options = - let - protect pageWithUser page = - Page - (\shared req -> - case options.user shared req of - Just user -> - Ok (pageWithUser user page) - - Nothing -> - Err options.route - ) - in - { static = - protect - (\user page -> - { init = \_ -> ( (), options.effectNone ) - , update = \_ model -> ( model, options.effectNone ) - , view = \_ -> page.view user - , subscriptions = \_ -> Sub.none - } - ) - , sandbox = - protect - (\user page -> - { init = \_ -> ( page.init user, options.effectNone ) - , update = \msg model -> ( page.update user msg model, options.effectNone ) - , view = page.view user - , subscriptions = \_ -> Sub.none - } - ) - , element = - protect - (\user page -> - { init = \_ -> page.init user |> Tuple.mapSecond options.fromCmd - , update = \msg model -> page.update user msg model |> Tuple.mapSecond options.fromCmd - , view = page.view user - , subscriptions = page.subscriptions user - } - ) - , advanced = - protect - (\user page -> - { init = \_ -> page.init user - , update = page.update user - , view = page.view user - , subscriptions = page.subscriptions user - } - ) - } + Page (\_ _ -> Ok (adapters.advanced page)) {-| Actions to take when a user visits a `protected` page @@ -311,101 +193,88 @@ type Protected user route Prefixing any of the four functions above with `protected` will guarantee that the page has access to a user. Here's an example with `sandbox`: - import Page + -- before + Page.sandbox + { init = init + , update = update + , view = view + } - page : Page Model Msg - page = - Page.protected.sandbox + -- after + Page.protected.sandbox + (\user -> { init = init , update = update , view = view } + ) - -- init : User -> Model - -- update : User -> Msg -> Model -> Model - -- update : User -> Model -> View Msg + -- other functions have same API + init : Model + update : Msg -> Model -> Model + view : Model -> View Msg -} -protected2 : +protected3 : { effectNone : effect , fromCmd : Cmd msg -> effect , beforeInit : shared -> Request route () -> Protected user route } -> { static : - { view : user -> view - } + (user + -> + { view : view + } + ) -> Page shared route effect view () msg , sandbox : - { init : user -> model - , update : user -> msg -> model -> model - , view : user -> model -> view - } + (user + -> + { init : model + , update : msg -> model -> model + , view : model -> view + } + ) -> Page shared route effect view model msg , element : - { init : user -> ( model, Cmd msg ) - , update : user -> msg -> model -> ( model, Cmd msg ) - , view : user -> model -> view - , subscriptions : user -> model -> Sub msg - } + (user + -> + { init : ( model, Cmd msg ) + , update : msg -> model -> ( model, Cmd msg ) + , view : model -> view + , subscriptions : model -> Sub msg + } + ) -> Page shared route effect view model msg , advanced : - { init : user -> ( model, effect ) - , update : user -> msg -> model -> ( model, effect ) - , view : user -> model -> view - , subscriptions : user -> model -> Sub msg - } + (user + -> + { init : ( model, effect ) + , update : msg -> model -> ( model, effect ) + , view : model -> view + , subscriptions : model -> Sub msg + } + ) -> Page shared route effect view model msg } -protected2 options = +protected3 options = let - protect pageWithUser page = + protect toPage toRecord = Page (\shared req -> case options.beforeInit shared req of Provide user -> - Ok (pageWithUser user page) + Ok (user |> toRecord |> toPage) RedirectTo route -> Err route ) in - { static = - protect - (\user page -> - { init = \_ -> ( (), options.effectNone ) - , update = \_ model -> ( model, options.effectNone ) - , view = \_ -> page.view user - , subscriptions = \_ -> Sub.none - } - ) - , sandbox = - protect - (\user page -> - { init = \_ -> ( page.init user, options.effectNone ) - , update = \msg model -> ( page.update user msg model, options.effectNone ) - , view = page.view user - , subscriptions = \_ -> Sub.none - } - ) - , element = - protect - (\user page -> - { init = \_ -> page.init user |> Tuple.mapSecond options.fromCmd - , update = \msg model -> page.update user msg model |> Tuple.mapSecond options.fromCmd - , view = page.view user - , subscriptions = page.subscriptions user - } - ) - , advanced = - protect - (\user page -> - { init = \_ -> page.init user - , update = page.update user - , view = page.view user - , subscriptions = page.subscriptions user - } - ) + { static = protect (adapters.static options.effectNone) + , sandbox = protect (adapters.sandbox options.effectNone) + , element = protect (adapters.element options.fromCmd) + , advanced = protect adapters.advanced } @@ -527,3 +396,242 @@ type alias PageRecord effect view model msg = , view : model -> view , subscriptions : model -> Sub msg } + + +adapters : + { static : + effect + -> + { view : view + } + -> PageRecord effect view () msg + , sandbox : + effect + -> + { init : model + , update : msg -> model -> model + , view : model -> view + } + -> PageRecord effect view model msg + , element : + (Cmd msg -> effect) + -> + { init : ( model, Cmd msg ) + , update : msg -> model -> ( model, Cmd msg ) + , view : model -> view + , subscriptions : model -> Sub msg + } + -> PageRecord effect view model msg + , advanced : + { init : ( model, effect ) + , update : msg -> model -> ( model, effect ) + , view : model -> view + , subscriptions : model -> Sub msg + } + -> PageRecord effect view model msg + } +adapters = + { static = + \none page -> + { init = \_ -> ( (), none ) + , update = \_ _ -> ( (), none ) + , view = \_ -> page.view + , subscriptions = \_ -> Sub.none + } + , sandbox = + \none page -> + { init = \_ -> ( page.init, none ) + , update = \msg model -> ( page.update msg model, none ) + , view = page.view + , subscriptions = \_ -> Sub.none + } + , element = + \fromCmd page -> + { init = \_ -> page.init |> Tuple.mapSecond fromCmd + , update = \msg model -> page.update msg model |> Tuple.mapSecond fromCmd + , view = page.view + , subscriptions = page.subscriptions + } + , advanced = + \page -> + { init = always page.init + , update = page.update + , view = page.view + , subscriptions = page.subscriptions + } + } + + + +-- DEPRECATED - will be removed in v6 + + +{-| Deprecated! Will be replaced by [protected3](#protected3) +-} +protected : + { effectNone : effect + , fromCmd : Cmd msg -> effect + , user : shared -> Request route () -> Maybe user + , route : route + } + -> + { static : + { view : user -> view + } + -> Page shared route effect view () msg + , sandbox : + { init : user -> model + , update : user -> msg -> model -> model + , view : user -> model -> view + } + -> Page shared route effect view model msg + , element : + { init : user -> ( model, Cmd msg ) + , update : user -> msg -> model -> ( model, Cmd msg ) + , view : user -> model -> view + , subscriptions : user -> model -> Sub msg + } + -> Page shared route effect view model msg + , advanced : + { init : user -> ( model, effect ) + , update : user -> msg -> model -> ( model, effect ) + , view : user -> model -> view + , subscriptions : user -> model -> Sub msg + } + -> Page shared route effect view model msg + } +protected options = + let + protect pageWithUser page = + Page + (\shared req -> + case options.user shared req of + Just user -> + Ok (pageWithUser user page) + + Nothing -> + Err options.route + ) + in + { static = + protect + (\user page -> + { init = \_ -> ( (), options.effectNone ) + , update = \_ model -> ( model, options.effectNone ) + , view = \_ -> page.view user + , subscriptions = \_ -> Sub.none + } + ) + , sandbox = + protect + (\user page -> + { init = \_ -> ( page.init user, options.effectNone ) + , update = \msg model -> ( page.update user msg model, options.effectNone ) + , view = page.view user + , subscriptions = \_ -> Sub.none + } + ) + , element = + protect + (\user page -> + { init = \_ -> page.init user |> Tuple.mapSecond options.fromCmd + , update = \msg model -> page.update user msg model |> Tuple.mapSecond options.fromCmd + , view = page.view user + , subscriptions = page.subscriptions user + } + ) + , advanced = + protect + (\user page -> + { init = \_ -> page.init user + , update = page.update user + , view = page.view user + , subscriptions = page.subscriptions user + } + ) + } + + +{-| Deprecated! Will be replaced by [protected3](#protected3) +-} +protected2 : + { effectNone : effect + , fromCmd : Cmd msg -> effect + , beforeInit : shared -> Request route () -> Protected user route + } + -> + { static : + { view : user -> view + } + -> Page shared route effect view () msg + , sandbox : + { init : user -> model + , update : user -> msg -> model -> model + , view : user -> model -> view + } + -> Page shared route effect view model msg + , element : + { init : user -> ( model, Cmd msg ) + , update : user -> msg -> model -> ( model, Cmd msg ) + , view : user -> model -> view + , subscriptions : user -> model -> Sub msg + } + -> Page shared route effect view model msg + , advanced : + { init : user -> ( model, effect ) + , update : user -> msg -> model -> ( model, effect ) + , view : user -> model -> view + , subscriptions : user -> model -> Sub msg + } + -> Page shared route effect view model msg + } +protected2 options = + let + protect pageWithUser page = + Page + (\shared req -> + case options.beforeInit shared req of + Provide user -> + Ok (pageWithUser user page) + + RedirectTo route -> + Err route + ) + in + { static = + protect + (\user page -> + { init = \_ -> ( (), options.effectNone ) + , update = \_ model -> ( model, options.effectNone ) + , view = \_ -> page.view user + , subscriptions = \_ -> Sub.none + } + ) + , sandbox = + protect + (\user page -> + { init = \_ -> ( page.init user, options.effectNone ) + , update = \msg model -> ( page.update user msg model, options.effectNone ) + , view = page.view user + , subscriptions = \_ -> Sub.none + } + ) + , element = + protect + (\user page -> + { init = \_ -> page.init user |> Tuple.mapSecond options.fromCmd + , update = \msg model -> page.update user msg model |> Tuple.mapSecond options.fromCmd + , view = page.view user + , subscriptions = page.subscriptions user + } + ) + , advanced = + protect + (\user page -> + { init = \_ -> page.init user + , update = page.update user + , view = page.view user + , subscriptions = page.subscriptions user + } + ) + } diff --git a/src/cli/src/new/elm.json b/src/cli/src/new/elm.json index 9cf94a9..e694c97 100644 --- a/src/cli/src/new/elm.json +++ b/src/cli/src/new/elm.json @@ -13,7 +13,7 @@ "elm/html": "1.0.0", "elm/json": "1.1.3", "elm/url": "1.0.0", - "ryannhg/elm-spa": "5.2.0" + "ryannhg/elm-spa": "5.3.0" }, "indirect": { "elm/time": "1.0.0", diff --git a/src/cli/src/templates/page.ts b/src/cli/src/templates/page.ts index 07232f8..4505915 100644 --- a/src/cli/src/templates/page.ts +++ b/src/cli/src/templates/page.ts @@ -80,32 +80,44 @@ advanced = protected : { static : - { view : User -> View msg - } + (User + -> + { view : View msg + } + ) -> With () msg , sandbox : - { init : User -> model - , update : User -> msg -> model -> model - , view : User -> model -> View msg - } + (User + -> + { init : model + , update : msg -> model -> model + , view : model -> View msg + } + ) -> With model msg , element : - { init : User -> ( model, Cmd msg ) - , update : User -> msg -> model -> ( model, Cmd msg ) - , view : User -> model -> View msg - , subscriptions : User -> model -> Sub msg - } + (User + -> + { init : ( model, Cmd msg ) + , update : msg -> model -> ( model, Cmd msg ) + , view : model -> View msg + , subscriptions : model -> Sub msg + } + ) -> With model msg , advanced : - { init : User -> ( model, Effect msg ) - , update : User -> msg -> model -> ( model, Effect msg ) - , view : User -> model -> View msg - , subscriptions : User -> model -> Sub msg - } + (User + -> + { init : ( model, Effect msg ) + , update : msg -> model -> ( model, Effect msg ) + , view : model -> View msg + , subscriptions : model -> Sub msg + } + ) -> With model msg } protected = - ElmSpa.protected2 + ElmSpa.protected3 { effectNone = Effect.none , fromCmd = Effect.fromCmd , beforeInit = Auth.beforeProtectedInit