elm-pages 3.0.0-beta.40 → 3.0.0-beta.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/codegen/elm-pages-codegen.cjs +204 -262
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/src/RouteBuilder.elm +9 -8
- package/generator/src/SharedTemplate.elm +5 -5
- package/generator/src/compatibility-key.js +2 -2
- package/package.json +1 -1
- package/src/BackendTask.elm +18 -24
- package/src/Head/Seo.elm +4 -4
- package/src/Pages/ConcurrentSubmission.elm +127 -0
- package/src/Pages/Form.elm +151 -40
- package/src/Pages/FormData.elm +18 -0
- package/src/Pages/Internal/NotFoundReason.elm +4 -4
- package/src/Pages/Internal/Platform/Cli.elm +15 -15
- package/src/Pages/Internal/Platform/CompatibilityKey.elm +1 -1
- package/src/Pages/Internal/Platform.elm +39 -38
- package/src/Pages/Internal/ResponseSketch.elm +2 -2
- package/src/Pages/Manifest.elm +23 -7
- package/src/Pages/Navigation.elm +87 -0
- package/src/Pages/PageUrl.elm +3 -3
- package/src/Pages/ProgramConfig.elm +10 -9
- package/src/Pages/Script.elm +64 -7
- package/src/Pages/Url.elm +3 -3
- package/src/PagesMsg.elm +9 -3
- package/src/RenderRequest.elm +7 -7
- package/src/Scaffold/Form.elm +28 -5
- package/src/Scaffold/Route.elm +12 -3
- package/src/Server/Request.elm +2 -1
- package/src/Server/Session.elm +1 -1
- package/src/Server/SetCookie.elm +71 -31
- package/src/{Path.elm → UrlPath.elm} +21 -21
- package/src/Pages/Transition.elm +0 -79
|
@@ -26,6 +26,7 @@ import Html.Attributes as Attr
|
|
|
26
26
|
import Http
|
|
27
27
|
import Json.Decode as Decode
|
|
28
28
|
import Json.Encode
|
|
29
|
+
import Pages.ConcurrentSubmission
|
|
29
30
|
import Pages.ContentCache as ContentCache
|
|
30
31
|
import Pages.Fetcher
|
|
31
32
|
import Pages.Flags
|
|
@@ -33,15 +34,15 @@ import Pages.Internal.Msg
|
|
|
33
34
|
import Pages.Internal.NotFoundReason exposing (NotFoundReason)
|
|
34
35
|
import Pages.Internal.ResponseSketch as ResponseSketch exposing (ResponseSketch)
|
|
35
36
|
import Pages.Internal.String as String
|
|
37
|
+
import Pages.Navigation
|
|
36
38
|
import Pages.ProgramConfig exposing (ProgramConfig)
|
|
37
39
|
import Pages.StaticHttpRequest as StaticHttpRequest
|
|
38
|
-
import Pages.Transition
|
|
39
40
|
import PagesMsg exposing (PagesMsg)
|
|
40
|
-
import Path exposing (Path)
|
|
41
41
|
import QueryParams
|
|
42
42
|
import Task
|
|
43
43
|
import Time
|
|
44
44
|
import Url exposing (Url)
|
|
45
|
+
import UrlPath exposing (UrlPath)
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
{-| -}
|
|
@@ -75,7 +76,7 @@ mainView config model =
|
|
|
75
76
|
(config.view model.pageFormState
|
|
76
77
|
(model.inFlightFetchers |> toFetcherState)
|
|
77
78
|
(model.transition |> Maybe.map Tuple.second)
|
|
78
|
-
{ path = ContentCache.pathForUrl urls |>
|
|
79
|
+
{ path = ContentCache.pathForUrl urls |> UrlPath.join
|
|
79
80
|
, route = config.urlToRoute { currentUrl | path = model.currentPath }
|
|
80
81
|
}
|
|
81
82
|
Nothing
|
|
@@ -95,14 +96,14 @@ mainView config model =
|
|
|
95
96
|
|
|
96
97
|
urlsToPagePath :
|
|
97
98
|
{ currentUrl : Url, basePath : List String }
|
|
98
|
-
->
|
|
99
|
+
-> UrlPath
|
|
99
100
|
urlsToPagePath urls =
|
|
100
101
|
urls.currentUrl.path
|
|
101
102
|
|> String.chopForwardSlashes
|
|
102
103
|
|> String.split "/"
|
|
103
104
|
|> List.filter ((/=) "")
|
|
104
105
|
|> List.drop (List.length urls.basePath)
|
|
105
|
-
|>
|
|
106
|
+
|> UrlPath.join
|
|
106
107
|
|
|
107
108
|
|
|
108
109
|
{-| -}
|
|
@@ -144,7 +145,7 @@ type alias Flags =
|
|
|
144
145
|
|
|
145
146
|
type InitKind shared page actionData errorPage
|
|
146
147
|
= OkPage shared page (Maybe actionData)
|
|
147
|
-
| NotFound { reason : NotFoundReason, path :
|
|
148
|
+
| NotFound { reason : NotFoundReason, path : UrlPath }
|
|
148
149
|
|
|
149
150
|
|
|
150
151
|
{-| -}
|
|
@@ -198,7 +199,7 @@ init config flags url key =
|
|
|
198
199
|
, basePath = config.basePath
|
|
199
200
|
}
|
|
200
201
|
|
|
201
|
-
pagePath :
|
|
202
|
+
pagePath : UrlPath
|
|
202
203
|
pagePath =
|
|
203
204
|
urlsToPagePath urls
|
|
204
205
|
|
|
@@ -338,11 +339,11 @@ type alias Model userModel pageData actionData sharedData =
|
|
|
338
339
|
, sharedData : sharedData
|
|
339
340
|
, actionData : Maybe actionData
|
|
340
341
|
}
|
|
341
|
-
, notFound : Maybe { reason : NotFoundReason, path :
|
|
342
|
+
, notFound : Maybe { reason : NotFoundReason, path : UrlPath }
|
|
342
343
|
, userFlags : Decode.Value
|
|
343
|
-
, transition : Maybe ( Int, Pages.
|
|
344
|
+
, transition : Maybe ( Int, Pages.Navigation.Navigation )
|
|
344
345
|
, nextTransitionKey : Int
|
|
345
|
-
, inFlightFetchers : Dict String ( Int, Pages.
|
|
346
|
+
, inFlightFetchers : Dict String ( Int, Pages.ConcurrentSubmission.ConcurrentSubmission actionData )
|
|
346
347
|
, pageFormState : Form.Model
|
|
347
348
|
, pendingRedirect : Bool
|
|
348
349
|
, pendingData : Maybe ( pageData, sharedData, Maybe actionData )
|
|
@@ -454,9 +455,9 @@ update config appMsg model =
|
|
|
454
455
|
, { fetcherState
|
|
455
456
|
| status =
|
|
456
457
|
maybeFetcherDoneActionData
|
|
457
|
-
|> Maybe.map Pages.
|
|
458
|
+
|> Maybe.map Pages.ConcurrentSubmission.Reloading
|
|
458
459
|
-- TODO remove this bad default, FetcherSubmitting is incorrect
|
|
459
|
-
|> Maybe.withDefault Pages.
|
|
460
|
+
|> Maybe.withDefault Pages.ConcurrentSubmission.Submitting
|
|
460
461
|
}
|
|
461
462
|
)
|
|
462
463
|
)
|
|
@@ -534,7 +535,7 @@ update config appMsg model =
|
|
|
534
535
|
Just
|
|
535
536
|
( -- TODO remove hardcoded number
|
|
536
537
|
-1
|
|
537
|
-
, Pages.
|
|
538
|
+
, Pages.Navigation.Submitting payload
|
|
538
539
|
)
|
|
539
540
|
}
|
|
540
541
|
, Submit payload
|
|
@@ -797,7 +798,7 @@ update config appMsg model =
|
|
|
797
798
|
, basePath = config.basePath
|
|
798
799
|
}
|
|
799
800
|
|
|
800
|
-
pagePath :
|
|
801
|
+
pagePath : UrlPath
|
|
801
802
|
pagePath =
|
|
802
803
|
urlsToPagePath urls
|
|
803
804
|
|
|
@@ -857,7 +858,7 @@ update config appMsg model =
|
|
|
857
858
|
|> Dict.insert fetcherKey
|
|
858
859
|
( transitionId
|
|
859
860
|
, { payload = fetcherData
|
|
860
|
-
, status = Pages.
|
|
861
|
+
, status = Pages.ConcurrentSubmission.Submitting
|
|
861
862
|
, initiatedAt = initiatedAt
|
|
862
863
|
}
|
|
863
864
|
)
|
|
@@ -866,7 +867,7 @@ update config appMsg model =
|
|
|
866
867
|
)
|
|
867
868
|
|
|
868
869
|
|
|
869
|
-
toFetcherState : Dict String ( Int, Pages.
|
|
870
|
+
toFetcherState : Dict String ( Int, Pages.ConcurrentSubmission.ConcurrentSubmission actionData ) -> Dict String (Pages.ConcurrentSubmission.ConcurrentSubmission actionData)
|
|
870
871
|
toFetcherState inFlightFetchers =
|
|
871
872
|
inFlightFetchers
|
|
872
873
|
|> Dict.map (\_ ( _, fetcherState ) -> fetcherState)
|
|
@@ -1050,7 +1051,7 @@ startFetcher fetcherKey transitionId options model =
|
|
|
1050
1051
|
, tracker = Nothing
|
|
1051
1052
|
, body = Http.stringBody "application/x-www-form-urlencoded" encodedBody
|
|
1052
1053
|
, headers = options.headers |> List.map (\( name, value ) -> Http.header name value)
|
|
1053
|
-
, url = options.url |> Maybe.withDefault (
|
|
1054
|
+
, url = options.url |> Maybe.withDefault (UrlPath.join [ model.url.path, "content.dat" ] |> UrlPath.toAbsolute)
|
|
1054
1055
|
, method = "POST"
|
|
1055
1056
|
, timeout = Nothing
|
|
1056
1057
|
}
|
|
@@ -1129,7 +1130,7 @@ startFetcher2 config fromPageReload fetcherKey transitionId formData model =
|
|
|
1129
1130
|
, headers = []
|
|
1130
1131
|
|
|
1131
1132
|
-- TODO use formData.method to do either query params or POST body
|
|
1132
|
-
, url = formData.action |> Url.fromString |> Maybe.map (\{ path } ->
|
|
1133
|
+
, url = formData.action |> Url.fromString |> Maybe.map (\{ path } -> UrlPath.join [ path, "content.dat" ] |> UrlPath.toAbsolute) |> Maybe.withDefault "/"
|
|
1133
1134
|
, method = formData.method |> methodToString
|
|
1134
1135
|
, timeout = Nothing
|
|
1135
1136
|
}
|
|
@@ -1143,14 +1144,14 @@ cancelStaleFetchers model =
|
|
|
1143
1144
|
|> List.filterMap
|
|
1144
1145
|
(\( _, ( id, fetcher ) ) ->
|
|
1145
1146
|
case fetcher.status of
|
|
1146
|
-
Pages.
|
|
1147
|
+
Pages.ConcurrentSubmission.Reloading _ ->
|
|
1147
1148
|
Http.cancel (String.fromInt id)
|
|
1148
1149
|
|> Just
|
|
1149
1150
|
|
|
1150
|
-
Pages.
|
|
1151
|
+
Pages.ConcurrentSubmission.Submitting ->
|
|
1151
1152
|
Nothing
|
|
1152
1153
|
|
|
1153
|
-
Pages.
|
|
1154
|
+
Pages.ConcurrentSubmission.Complete _ ->
|
|
1154
1155
|
Nothing
|
|
1155
1156
|
)
|
|
1156
1157
|
|> Cmd.batch
|
|
@@ -1207,7 +1208,7 @@ application config =
|
|
|
1207
1208
|
in
|
|
1208
1209
|
Sub.batch
|
|
1209
1210
|
[ config.subscriptions (model.url |> config.urlToRoute)
|
|
1210
|
-
(urls.currentUrl |> config.urlToRoute |> config.routeToPath |>
|
|
1211
|
+
(urls.currentUrl |> config.urlToRoute |> config.routeToPath |> UrlPath.join)
|
|
1211
1212
|
pageData.userModel
|
|
1212
1213
|
|> Sub.map (Pages.Internal.Msg.UserMsg >> UserMsg)
|
|
1213
1214
|
, config.hotReloadData
|
|
@@ -1256,9 +1257,9 @@ withUserMsg config userMsg ( model, effect ) =
|
|
|
1256
1257
|
( model, effect )
|
|
1257
1258
|
|
|
1258
1259
|
|
|
1259
|
-
urlPathToPath : Url ->
|
|
1260
|
+
urlPathToPath : Url -> UrlPath
|
|
1260
1261
|
urlPathToPath urls =
|
|
1261
|
-
urls.path |>
|
|
1262
|
+
urls.path |> UrlPath.fromString
|
|
1262
1263
|
|
|
1263
1264
|
|
|
1264
1265
|
fetchRouteData :
|
|
@@ -1407,7 +1408,7 @@ startNewGetLoad urlToGet toMsg ( model, effect ) =
|
|
|
1407
1408
|
cancelIfStale : Effect userMsg pageData actionData sharedData userEffect errorPage
|
|
1408
1409
|
cancelIfStale =
|
|
1409
1410
|
case model.transition of
|
|
1410
|
-
Just ( transitionKey, Pages.
|
|
1411
|
+
Just ( transitionKey, Pages.Navigation.Loading _ _ ) ->
|
|
1411
1412
|
CancelRequest transitionKey
|
|
1412
1413
|
|
|
1413
1414
|
_ ->
|
|
@@ -1418,22 +1419,22 @@ startNewGetLoad urlToGet toMsg ( model, effect ) =
|
|
|
1418
1419
|
, transition =
|
|
1419
1420
|
( model.nextTransitionKey
|
|
1420
1421
|
, case model.transition of
|
|
1421
|
-
Just ( _, Pages.
|
|
1422
|
-
Pages.
|
|
1422
|
+
Just ( _, Pages.Navigation.LoadAfterSubmit submitData _ _ ) ->
|
|
1423
|
+
Pages.Navigation.LoadAfterSubmit
|
|
1423
1424
|
submitData
|
|
1424
|
-
(urlToGet.path |>
|
|
1425
|
-
Pages.
|
|
1425
|
+
(urlToGet.path |> UrlPath.fromString)
|
|
1426
|
+
Pages.Navigation.Load
|
|
1426
1427
|
|
|
1427
|
-
Just ( _, Pages.
|
|
1428
|
-
Pages.
|
|
1428
|
+
Just ( _, Pages.Navigation.Submitting submitData ) ->
|
|
1429
|
+
Pages.Navigation.LoadAfterSubmit
|
|
1429
1430
|
submitData
|
|
1430
|
-
(urlToGet.path |>
|
|
1431
|
-
Pages.
|
|
1431
|
+
(urlToGet.path |> UrlPath.fromString)
|
|
1432
|
+
Pages.Navigation.Load
|
|
1432
1433
|
|
|
1433
1434
|
_ ->
|
|
1434
|
-
Pages.
|
|
1435
|
-
(urlToGet.path |>
|
|
1436
|
-
Pages.
|
|
1435
|
+
Pages.Navigation.Loading
|
|
1436
|
+
(urlToGet.path |> UrlPath.fromString)
|
|
1437
|
+
Pages.Navigation.Load
|
|
1437
1438
|
)
|
|
1438
1439
|
|> Just
|
|
1439
1440
|
}
|
|
@@ -1459,9 +1460,9 @@ clearLoadingFetchersAfterDataLoad completedTransitionId model =
|
|
|
1459
1460
|
-- TODO fetchers are never removed from the list. Need to decide how and when to remove them.
|
|
1460
1461
|
--(fetcherState.status /= Pages.Transition.FetcherReloading) || (transitionId > completedTransitionId)
|
|
1461
1462
|
case ( transitionId > completedTransitionId, fetcherState.status ) of
|
|
1462
|
-
( False, Pages.
|
|
1463
|
+
( False, Pages.ConcurrentSubmission.Reloading actionData ) ->
|
|
1463
1464
|
( transitionId
|
|
1464
|
-
, { fetcherState | status = Pages.
|
|
1465
|
+
, { fetcherState | status = Pages.ConcurrentSubmission.Complete actionData }
|
|
1465
1466
|
)
|
|
1466
1467
|
|
|
1467
1468
|
_ ->
|
|
@@ -7,7 +7,7 @@ module Pages.Internal.ResponseSketch exposing (ResponseSketch(..))
|
|
|
7
7
|
-}
|
|
8
8
|
|
|
9
9
|
import Pages.Internal.NotFoundReason exposing (NotFoundReason)
|
|
10
|
-
import
|
|
10
|
+
import UrlPath exposing (UrlPath)
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
{-| -}
|
|
@@ -15,5 +15,5 @@ type ResponseSketch data action shared
|
|
|
15
15
|
= RenderPage data (Maybe action)
|
|
16
16
|
| HotUpdate data shared (Maybe action)
|
|
17
17
|
| Redirect String
|
|
18
|
-
| NotFound { reason : NotFoundReason, path :
|
|
18
|
+
| NotFound { reason : NotFoundReason, path : UrlPath }
|
|
19
19
|
| Action action
|
package/src/Pages/Manifest.elm
CHANGED
|
@@ -11,8 +11,8 @@ module Pages.Manifest exposing
|
|
|
11
11
|
{-| Represents the configuration of a
|
|
12
12
|
[web manifest file](https://developer.mozilla.org/en-US/docs/Web/Manifest).
|
|
13
13
|
|
|
14
|
-
You pass your `Pages.Manifest.Config` record into the `Pages.
|
|
15
|
-
|
|
14
|
+
You pass your `Pages.Manifest.Config` record into the `Pages.Manifest.generator`
|
|
15
|
+
in your `app/Api.elm` module to define a file generator that will build a `manifest.json` file as part of your build.
|
|
16
16
|
|
|
17
17
|
import Pages.Manifest as Manifest
|
|
18
18
|
import Pages.Manifest.Category
|
|
@@ -77,7 +77,7 @@ import LanguageTag.Language
|
|
|
77
77
|
import MimeType
|
|
78
78
|
import Pages.Manifest.Category as Category exposing (Category)
|
|
79
79
|
import Pages.Url
|
|
80
|
-
import
|
|
80
|
+
import UrlPath exposing (UrlPath)
|
|
81
81
|
|
|
82
82
|
|
|
83
83
|
|
|
@@ -114,7 +114,7 @@ type Orientation
|
|
|
114
114
|
init :
|
|
115
115
|
{ description : String
|
|
116
116
|
, name : String
|
|
117
|
-
, startUrl :
|
|
117
|
+
, startUrl : UrlPath
|
|
118
118
|
, icons : List Icon
|
|
119
119
|
}
|
|
120
120
|
-> Config
|
|
@@ -253,7 +253,7 @@ type alias Config =
|
|
|
253
253
|
, themeColor : Maybe Color
|
|
254
254
|
|
|
255
255
|
-- https://developer.mozilla.org/en-US/docs/Web/Manifest/start_url
|
|
256
|
-
, startUrl :
|
|
256
|
+
, startUrl : UrlPath
|
|
257
257
|
|
|
258
258
|
-- https://developer.mozilla.org/en-US/docs/Web/Manifest/short_name
|
|
259
259
|
, shortName : Maybe String
|
|
@@ -343,7 +343,23 @@ nonEmptyList list =
|
|
|
343
343
|
Just list
|
|
344
344
|
|
|
345
345
|
|
|
346
|
-
{-| A generator for Api.elm to include a manifest.json.
|
|
346
|
+
{-| A generator for `Api.elm` to include a manifest.json. The String argument is the canonical URL of the site.
|
|
347
|
+
|
|
348
|
+
module Api exposing (routes)
|
|
349
|
+
|
|
350
|
+
import ApiRoute
|
|
351
|
+
import Pages.Manifest
|
|
352
|
+
|
|
353
|
+
routes :
|
|
354
|
+
BackendTask FatalError (List Route)
|
|
355
|
+
-> (Maybe { indent : Int, newLines : Bool } -> Html Never -> String)
|
|
356
|
+
-> List (ApiRoute.ApiRoute ApiRoute.Response)
|
|
357
|
+
routes getStaticRoutes htmlToString =
|
|
358
|
+
[ Pages.Manifest.generator
|
|
359
|
+
Site.canonicalUrl
|
|
360
|
+
Manifest.config
|
|
361
|
+
]
|
|
362
|
+
|
|
347
363
|
-}
|
|
348
364
|
generator : String -> BackendTask FatalError Config -> ApiRoute.ApiRoute ApiRoute.Response
|
|
349
365
|
generator canonicalSiteUrl config =
|
|
@@ -430,7 +446,7 @@ toJson canonicalSiteUrl config =
|
|
|
430
446
|
|> Maybe.map Encode.string
|
|
431
447
|
)
|
|
432
448
|
, ( "start_url"
|
|
433
|
-
,
|
|
449
|
+
, UrlPath.toAbsolute config.startUrl
|
|
434
450
|
|> Encode.string
|
|
435
451
|
|> Just
|
|
436
452
|
)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module Pages.Navigation exposing (Navigation(..), LoadingState(..))
|
|
2
|
+
|
|
3
|
+
{-| `elm-pages` maintains a single `Maybe Navigation` state which is accessible from your `Route` modules through `app.navigation`.
|
|
4
|
+
|
|
5
|
+
You can use it to show a loading indicator while a page is loading:
|
|
6
|
+
|
|
7
|
+
import Pages.Navigation as Navigation
|
|
8
|
+
|
|
9
|
+
pageLoadingIndicator app =
|
|
10
|
+
case app.navigation of
|
|
11
|
+
Just (Navigation.Loading path _) ->
|
|
12
|
+
Spinner.view
|
|
13
|
+
|
|
14
|
+
Nothing ->
|
|
15
|
+
emptyView
|
|
16
|
+
|
|
17
|
+
emptyView : Html msg
|
|
18
|
+
emptyView =
|
|
19
|
+
Html.text ""
|
|
20
|
+
|
|
21
|
+
You can also use it to derive Pending UI or Optimistic UI from a pending form submission:
|
|
22
|
+
|
|
23
|
+
import Form
|
|
24
|
+
import Form.Handler
|
|
25
|
+
import Pages.Navigation as Navigation
|
|
26
|
+
|
|
27
|
+
view app =
|
|
28
|
+
let
|
|
29
|
+
optimisticProduct : Maybe Product
|
|
30
|
+
optimisticProduct =
|
|
31
|
+
case app.navigation of
|
|
32
|
+
Just (Navigation.Submitting formData) ->
|
|
33
|
+
formHandler
|
|
34
|
+
|> Form.Handler.run formData
|
|
35
|
+
|> Form.toResult
|
|
36
|
+
|> Result.toMaybe
|
|
37
|
+
|
|
38
|
+
Just (Navigation.LoadAfterSubmit formData path _) ->
|
|
39
|
+
formHandler
|
|
40
|
+
|> Form.Handler.run formData
|
|
41
|
+
|> Form.toResult
|
|
42
|
+
|> Result.toMaybe
|
|
43
|
+
|
|
44
|
+
Nothing ->
|
|
45
|
+
Nothing
|
|
46
|
+
in
|
|
47
|
+
-- our `productsView` function could show a loading spinner (Pending UI),
|
|
48
|
+
-- or it could assume the product will be created successfully (Optimistic UI) and
|
|
49
|
+
-- display it as a regular product in the list
|
|
50
|
+
productsView optimisticProduct app.data.products
|
|
51
|
+
|
|
52
|
+
allForms : Form.Handler.Handler String Product
|
|
53
|
+
allForms =
|
|
54
|
+
Form.Handler.init identity productForm
|
|
55
|
+
|
|
56
|
+
editItemForm : Form.HtmlForm String Product input msg
|
|
57
|
+
editItemForm =
|
|
58
|
+
Debug.todo "Form definition here"
|
|
59
|
+
|
|
60
|
+
@docs Navigation, LoadingState
|
|
61
|
+
|
|
62
|
+
-}
|
|
63
|
+
|
|
64
|
+
import Form
|
|
65
|
+
import Pages.FormData exposing (FormData)
|
|
66
|
+
import Time
|
|
67
|
+
import UrlPath exposing (UrlPath)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
{-| Represents the global page navigation state of the app.
|
|
71
|
+
|
|
72
|
+
- `Loading` - navigating to a page, for example from a link click, or from a programmatic navigation with `Browser.Navigation.pushUrl`.
|
|
73
|
+
- `Submitting` - submitting a form using the default submission strategy (note that Forms rendered with the [`Pages.Form.withConcurrent`](Pages-Form#withConcurrent) Option have their state managed in `app.concurrentSubmissions` instead of `app.navigation`).
|
|
74
|
+
- `LoadAfterSubmit` - the state immediately after `Submitting` - allows you to continue using the `FormData` from a submission while a data reload or redirect is occurring.
|
|
75
|
+
|
|
76
|
+
-}
|
|
77
|
+
type Navigation
|
|
78
|
+
= Submitting FormData
|
|
79
|
+
| LoadAfterSubmit FormData UrlPath LoadingState
|
|
80
|
+
| Loading UrlPath LoadingState
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
{-| -}
|
|
84
|
+
type LoadingState
|
|
85
|
+
= Redirecting
|
|
86
|
+
| Load
|
|
87
|
+
| ActionRedirect
|
package/src/Pages/PageUrl.elm
CHANGED
|
@@ -13,9 +13,9 @@ the query params are parsed into a `Dict String (List String)`.
|
|
|
13
13
|
-}
|
|
14
14
|
|
|
15
15
|
import Dict exposing (Dict)
|
|
16
|
-
import Path exposing (Path)
|
|
17
16
|
import QueryParams
|
|
18
17
|
import Url
|
|
18
|
+
import UrlPath exposing (UrlPath)
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
{-| -}
|
|
@@ -23,7 +23,7 @@ type alias PageUrl =
|
|
|
23
23
|
{ protocol : Url.Protocol
|
|
24
24
|
, host : String
|
|
25
25
|
, port_ : Maybe Int
|
|
26
|
-
, path :
|
|
26
|
+
, path : UrlPath
|
|
27
27
|
, query : Dict String (List String)
|
|
28
28
|
, fragment : Maybe String
|
|
29
29
|
}
|
|
@@ -35,7 +35,7 @@ toUrl url =
|
|
|
35
35
|
{ protocol = url.protocol
|
|
36
36
|
, host = url.host
|
|
37
37
|
, port_ = url.port_
|
|
38
|
-
, path = url.path |>
|
|
38
|
+
, path = url.path |> UrlPath.toRelative
|
|
39
39
|
, query =
|
|
40
40
|
if url.query |> Dict.isEmpty then
|
|
41
41
|
Nothing
|
|
@@ -15,18 +15,19 @@ import Http
|
|
|
15
15
|
import Json.Decode as Decode
|
|
16
16
|
import Json.Encode
|
|
17
17
|
import PageServerResponse exposing (PageServerResponse)
|
|
18
|
+
import Pages.ConcurrentSubmission
|
|
18
19
|
import Pages.Fetcher
|
|
19
20
|
import Pages.Flags
|
|
20
21
|
import Pages.Internal.NotFoundReason exposing (NotFoundReason)
|
|
21
22
|
import Pages.Internal.Platform.ToJsPayload
|
|
22
23
|
import Pages.Internal.ResponseSketch exposing (ResponseSketch)
|
|
23
24
|
import Pages.Internal.RoutePattern exposing (RoutePattern)
|
|
25
|
+
import Pages.Navigation
|
|
24
26
|
import Pages.PageUrl exposing (PageUrl)
|
|
25
27
|
import Pages.SiteConfig exposing (SiteConfig)
|
|
26
|
-
import Pages.Transition
|
|
27
28
|
import PagesMsg exposing (PagesMsg)
|
|
28
|
-
import Path exposing (Path)
|
|
29
29
|
import Url exposing (Url)
|
|
30
|
+
import UrlPath exposing (UrlPath)
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
type alias ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage =
|
|
@@ -38,7 +39,7 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData
|
|
|
38
39
|
->
|
|
39
40
|
Maybe
|
|
40
41
|
{ path :
|
|
41
|
-
{ path :
|
|
42
|
+
{ path : UrlPath
|
|
42
43
|
, query : Maybe String
|
|
43
44
|
, fragment : Maybe String
|
|
44
45
|
}
|
|
@@ -46,18 +47,18 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData
|
|
|
46
47
|
, pageUrl : Maybe PageUrl
|
|
47
48
|
}
|
|
48
49
|
-> ( userModel, effect )
|
|
49
|
-
, update : Form.Model -> Dict String (Pages.
|
|
50
|
-
, subscriptions : route ->
|
|
50
|
+
, update : Form.Model -> Dict String (Pages.ConcurrentSubmission.ConcurrentSubmission actionData) -> Maybe Pages.Navigation.Navigation -> sharedData -> pageData -> Maybe Browser.Navigation.Key -> userMsg -> userModel -> ( userModel, effect )
|
|
51
|
+
, subscriptions : route -> UrlPath -> userModel -> Sub userMsg
|
|
51
52
|
, sharedData : BackendTask FatalError sharedData
|
|
52
53
|
, data : Decode.Value -> route -> BackendTask FatalError (PageServerResponse pageData errorPage)
|
|
53
54
|
, action : Decode.Value -> route -> BackendTask FatalError (PageServerResponse actionData errorPage)
|
|
54
55
|
, onActionData : actionData -> Maybe userMsg
|
|
55
56
|
, view :
|
|
56
57
|
Form.Model
|
|
57
|
-
-> Dict String (Pages.
|
|
58
|
-
-> Maybe Pages.
|
|
58
|
+
-> Dict String (Pages.ConcurrentSubmission.ConcurrentSubmission actionData)
|
|
59
|
+
-> Maybe Pages.Navigation.Navigation
|
|
59
60
|
->
|
|
60
|
-
{ path :
|
|
61
|
+
{ path : UrlPath
|
|
61
62
|
, route : route
|
|
62
63
|
}
|
|
63
64
|
-> Maybe PageUrl
|
|
@@ -81,7 +82,7 @@ type alias ProgramConfig userMsg userModel route pageData actionData sharedData
|
|
|
81
82
|
{ protocol : Url.Protocol
|
|
82
83
|
, host : String
|
|
83
84
|
, port_ : Maybe Int
|
|
84
|
-
, path :
|
|
85
|
+
, path : UrlPath
|
|
85
86
|
, query : Maybe String
|
|
86
87
|
, fragment : Maybe String
|
|
87
88
|
, metadata : route
|
package/src/Pages/Script.elm
CHANGED
|
@@ -6,10 +6,15 @@ module Pages.Script exposing
|
|
|
6
6
|
, Error(..)
|
|
7
7
|
)
|
|
8
8
|
|
|
9
|
-
{-|
|
|
9
|
+
{-| An elm-pages Script is a way to execute an `elm-pages` `BackendTask`.
|
|
10
|
+
|
|
11
|
+
Read more about using the `elm-pages` CLI to run (or bundle) scripts, plus a brief tutorial, at <https://elm-pages-v3.netlify.app/docs/elm-pages-scripts>.
|
|
10
12
|
|
|
11
13
|
@docs Script
|
|
12
14
|
|
|
15
|
+
|
|
16
|
+
## Defining Scripts
|
|
17
|
+
|
|
13
18
|
@docs withCliOptions, withoutCliOptions
|
|
14
19
|
|
|
15
20
|
|
|
@@ -40,18 +45,37 @@ import Json.Encode as Encode
|
|
|
40
45
|
import Pages.Internal.Script
|
|
41
46
|
|
|
42
47
|
|
|
43
|
-
{-| -
|
|
48
|
+
{-| The type for your `run` function that can be executed by `elm-pages run`.
|
|
49
|
+
-}
|
|
44
50
|
type alias Script =
|
|
45
51
|
Pages.Internal.Script.Script
|
|
46
52
|
|
|
47
53
|
|
|
48
|
-
{-|
|
|
54
|
+
{-| The recoverable error type for file writes. You can use `BackendTask.allowFatal` if you want to allow the program to crash
|
|
55
|
+
with an error message if a file write is unsuccessful.
|
|
56
|
+
-}
|
|
49
57
|
type Error
|
|
50
58
|
= --TODO make more descriptive
|
|
51
59
|
FileWriteError
|
|
52
60
|
|
|
53
61
|
|
|
54
|
-
{-|
|
|
62
|
+
{-| Write a file to the file system.
|
|
63
|
+
|
|
64
|
+
module MyScript exposing (run)
|
|
65
|
+
|
|
66
|
+
import BackendTask
|
|
67
|
+
import Pages.Script as Script
|
|
68
|
+
|
|
69
|
+
run =
|
|
70
|
+
Script.withoutCliOptions
|
|
71
|
+
(Script.writeFile
|
|
72
|
+
{ path = "hello.json"
|
|
73
|
+
, body = """{ "message": "Hello, World!" }"""
|
|
74
|
+
}
|
|
75
|
+
|> BackendTask.allowFatal
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
-}
|
|
55
79
|
writeFile : { path : String, body : String } -> BackendTask { fatal : FatalError, recoverable : Error } ()
|
|
56
80
|
writeFile { path, body } =
|
|
57
81
|
BackendTask.Internal.Request.request
|
|
@@ -69,7 +93,20 @@ writeFile { path, body } =
|
|
|
69
93
|
}
|
|
70
94
|
|
|
71
95
|
|
|
72
|
-
{-|
|
|
96
|
+
{-| Log to stdout.
|
|
97
|
+
|
|
98
|
+
module MyScript exposing (run)
|
|
99
|
+
|
|
100
|
+
import BackendTask
|
|
101
|
+
import Pages.Script as Script
|
|
102
|
+
|
|
103
|
+
run =
|
|
104
|
+
Script.withoutCliOptions
|
|
105
|
+
(Script.log "Hello!"
|
|
106
|
+
|> BackendTask.allowFatal
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
-}
|
|
73
110
|
log : String -> BackendTask error ()
|
|
74
111
|
log message =
|
|
75
112
|
BackendTask.Internal.Request.request
|
|
@@ -84,7 +121,20 @@ log message =
|
|
|
84
121
|
}
|
|
85
122
|
|
|
86
123
|
|
|
87
|
-
{-|
|
|
124
|
+
{-| Define a simple Script (no CLI Options).
|
|
125
|
+
|
|
126
|
+
module MyScript exposing (run)
|
|
127
|
+
|
|
128
|
+
import BackendTask
|
|
129
|
+
import Pages.Script as Script
|
|
130
|
+
|
|
131
|
+
run =
|
|
132
|
+
Script.withoutCliOptions
|
|
133
|
+
(Script.log "Hello!"
|
|
134
|
+
|> BackendTask.allowFatal
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
-}
|
|
88
138
|
withoutCliOptions : BackendTask FatalError () -> Script
|
|
89
139
|
withoutCliOptions execute =
|
|
90
140
|
Pages.Internal.Script.Script
|
|
@@ -99,7 +149,14 @@ withoutCliOptions execute =
|
|
|
99
149
|
)
|
|
100
150
|
|
|
101
151
|
|
|
102
|
-
{-|
|
|
152
|
+
{-| Same as [`withoutCliOptions`](#withoutCliOptions), but allows you to define a CLI Options Parser so the user can
|
|
153
|
+
pass in additional options for the script.
|
|
154
|
+
|
|
155
|
+
Uses <https://package.elm-lang.org/packages/dillonkearns/elm-cli-options-parser/latest/>.
|
|
156
|
+
|
|
157
|
+
Read more at <https://elm-pages-v3.netlify.app/docs/elm-pages-scripts/#adding-command-line-options>.
|
|
158
|
+
|
|
159
|
+
-}
|
|
103
160
|
withCliOptions : Program.Config cliOptions -> (cliOptions -> BackendTask FatalError ()) -> Script
|
|
104
161
|
withCliOptions config execute =
|
|
105
162
|
Pages.Internal.Script.Script
|
package/src/Pages/Url.elm
CHANGED
|
@@ -12,7 +12,7 @@ If you refer to a local page, like `Route.Index |> Route.toPath |> Pages.Url.fro
|
|
|
12
12
|
-}
|
|
13
13
|
|
|
14
14
|
import Pages.Internal.String as String
|
|
15
|
-
import
|
|
15
|
+
import UrlPath exposing (UrlPath)
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
{-| -}
|
|
@@ -22,9 +22,9 @@ type Url
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
{-| -}
|
|
25
|
-
fromPath :
|
|
25
|
+
fromPath : UrlPath -> Url
|
|
26
26
|
fromPath path =
|
|
27
|
-
path |>
|
|
27
|
+
path |> UrlPath.toAbsolute |> Internal
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
{-| -}
|
package/src/PagesMsg.elm
CHANGED
|
@@ -27,6 +27,8 @@ type alias PagesMsg userMsg =
|
|
|
27
27
|
|
|
28
28
|
{-|
|
|
29
29
|
|
|
30
|
+
import Form
|
|
31
|
+
import Pages.Form
|
|
30
32
|
import PagesMsg exposing (PagesMsg)
|
|
31
33
|
|
|
32
34
|
type Msg
|
|
@@ -46,10 +48,14 @@ type alias PagesMsg userMsg =
|
|
|
46
48
|
[ onClick (PagesMsg.fromMsg ToggleMenu) ]
|
|
47
49
|
[]
|
|
48
50
|
|
|
49
|
-
-- `Form.renderHtml` gives us `Html (PagesMsg msg)`, so we don't need to wrap its Msg type
|
|
51
|
+
-- `Pages.Form.renderHtml` gives us `Html (PagesMsg msg)`, so we don't need to wrap its Msg type
|
|
50
52
|
, logoutForm
|
|
51
|
-
|> Form.
|
|
52
|
-
|
|
53
|
+
|> Pages.Form.renderHtml []
|
|
54
|
+
Pages.Form.Serial
|
|
55
|
+
(Form.options "logout"
|
|
56
|
+
|> Form.withOnSubmit (\_ -> NewItemSubmitted)
|
|
57
|
+
)
|
|
58
|
+
app
|
|
53
59
|
]
|
|
54
60
|
}
|
|
55
61
|
|