Skip to content

Commit

Permalink
fix: Warn on session data decoding error. (#884)
Browse files Browse the repository at this point in the history
Warn users when decoding their session has failed, with useful
information on how to report the problem and reset the session
  • Loading branch information
n1k0 authored Jan 8, 2025
1 parent f8ffbcd commit 2601218
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 53 deletions.
47 changes: 19 additions & 28 deletions src/Data/Session.elm
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ module Data.Session exposing
, authenticated
, checkComparedSimulations
, closeNotification
, decodeRawStore
, defaultStore
, deleteBookmark
, deserializeStore
, getUser
, isAuthenticated
, logout
Expand Down Expand Up @@ -80,6 +81,7 @@ type alias EnabledSections =
type Notification
= GenericError String String
| GenericInfo String String
| StoreDecodingError Decode.Error


closeNotification : Notification -> Session -> Session
Expand All @@ -97,6 +99,11 @@ notifyError title error ({ notifications } as session) =
{ session | notifications = notifications ++ [ GenericError title error ] }


notifyStoreDecodingError : Decode.Error -> Session -> Session
notifyStoreDecodingError error ({ notifications } as session) =
{ session | notifications = notifications ++ [ StoreDecodingError error ] }



-- Boomarks

Expand Down Expand Up @@ -219,13 +226,9 @@ selectNoBookmarks =
updateStore (\store -> { store | comparedSimulations = Set.empty })



-- Store
--
-- A serializable data structure holding session information you want to share
-- across browser restarts, typically in localStorage.


{-| A serializable data structure holding session information you want to share
across browser restarts, typically in localStorage.
-}
type alias Store =
{ auth : Auth
, bookmarks : List Bookmark
Expand Down Expand Up @@ -289,26 +292,14 @@ getUser { store } =
Nothing


deserializeStore : String -> Store
deserializeStore =
Decode.decodeString decodeStore
-- FIXME: this should return a `Result String Store` so we could inform
-- users something went wrong while decoding their data (eg. so they can
-- report the issue).
-- Meanwhile, if you ever need to debug JSON decode errors from session
-- store, uncomment these lines.
-- >> (\res ->
-- case res of
-- Ok r ->
-- Ok r
-- Err err ->
-- let
-- _ =
-- Debug.log "deserializeStore error" err
-- in
-- Err err
-- )
>> Result.withDefault defaultStore
decodeRawStore : String -> Session -> Session
decodeRawStore rawStore session =
case Decode.decodeString decodeStore rawStore of
Err error ->
session |> notifyStoreDecodingError error

Ok store ->
{ session | store = store }


serializeStore : Store -> String
Expand Down
58 changes: 34 additions & 24 deletions src/Main.elm
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ type Msg
| OpenMobileNavigation
| ReleasesReceived (WebData (List Github.Release))
| ReloadPage
| ResetSessionStore
| StatsMsg Stats.Msg
| StoreChanged String
| SwitchVersion String
Expand Down Expand Up @@ -137,30 +138,27 @@ init flags requestedUrl navKey =

setupSession : Nav.Key -> Flags -> Db -> Session
setupSession navKey flags db =
let
store =
Session.deserializeStore flags.rawStore
in
{ clientUrl = flags.clientUrl
, currentVersion = Request.Version.Unknown
, db = db
, enabledSections = flags.enabledSections
, matomo = flags.matomo
, navKey = navKey
, notifications = []
, queries =
{ food = FoodQuery.empty
, object = ObjectQuery.default
, textile =
db.textile.examples
|> Example.findByName "Tshirt coton (150g) - Majorant par défaut"
|> Result.map .query
|> Result.withDefault TextileQuery.default
, veli = ObjectQuery.default
Session.decodeRawStore flags.rawStore
{ clientUrl = flags.clientUrl
, currentVersion = Request.Version.Unknown
, db = db
, enabledSections = flags.enabledSections
, matomo = flags.matomo
, navKey = navKey
, notifications = []
, queries =
{ food = FoodQuery.empty
, object = ObjectQuery.default
, textile =
db.textile.examples
|> Example.findByName "Tshirt coton (150g) - Majorant par défaut"
|> Result.map .query
|> Result.withDefault TextileQuery.default
, veli = ObjectQuery.default
}
, releases = RemoteData.NotAsked
, store = Session.defaultStore
}
, releases = RemoteData.NotAsked
, store = store
}


setRoute : Url -> ( Model, Cmd Msg ) -> ( Model, Cmd Msg )
Expand Down Expand Up @@ -353,11 +351,22 @@ update rawMsg ({ state } as model) =
( StoreChanged json, currentPage ) ->
( { model
| state =
currentPage |> Loaded { session | store = Session.deserializeStore json }
currentPage
|> Loaded (session |> Session.decodeRawStore json)
}
, Cmd.none
)

( ResetSessionStore, currentPage ) ->
let
newSession =
{ session | notifications = [], store = Session.defaultStore }
|> Session.notifyInfo "Session" "La session a été réinitialisée."
in
( { model | state = currentPage |> Loaded newSession }
, newSession.store |> Session.serializeStore |> Ports.saveStore
)

-- Version switch
( SwitchVersion version, _ ) ->
( model
Expand Down Expand Up @@ -478,6 +487,7 @@ view { mobileNavigationOpened, state } =
LoadUrl
ReloadPage
CloseNotification
ResetSessionStore
SwitchVersion

mapMsg msg ( title, content ) =
Expand Down
7 changes: 7 additions & 0 deletions src/Views/Alert.elm
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Level
= Danger
| Info
| Success
| Warning


icon : Level -> Html msg
Expand All @@ -40,6 +41,9 @@ icon level =
Success ->
span [ class "me-1" ] [ Icon.checkCircle ]

Warning ->
span [ class "me-1" ] [ Icon.warning ]


httpError : Http.Error -> Html msg
httpError error =
Expand Down Expand Up @@ -125,3 +129,6 @@ levelToClass level =

Success ->
"success"

Warning ->
"warning"
19 changes: 18 additions & 1 deletion src/Views/Page.elm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Data.Session as Session exposing (Session)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Json.Decode as Decode
import RemoteData
import Request.Version as Version exposing (Version(..))
import Route
Expand Down Expand Up @@ -53,6 +54,7 @@ type alias Config msg =
, loadUrl : String -> msg
, reloadPage : msg
, closeNotification : Session.Notification -> msg
, resetSessionStore : msg
, switchVersion : String -> msg
, activePage : ActivePage
}
Expand Down Expand Up @@ -436,7 +438,7 @@ notificationListView ({ session } as config) =


notificationView : Config msg -> Session.Notification -> Html msg
notificationView { closeNotification } notification =
notificationView { closeNotification, resetSessionStore } notification =
-- TODO:
-- - absolute positionning
case notification of
Expand All @@ -456,6 +458,21 @@ notificationView { closeNotification } notification =
, content = [ text message ]
}

Session.StoreDecodingError decodeError ->
Alert.simple
{ level = Alert.Warning
, title = Just "Erreur de récupération de session"
, close = Nothing
, content =
[ p [] [ text "Votre précédente session n'a pas pu être récupérée, elle doit donc être réinitialisée." ]
, p [] [ button [ class "btn btn-primary", onClick resetSessionStore ] [ text "D’accord, réinitialiser la session" ] ]
, details []
[ summary [] [ text "Afficher les détails techniques de l'erreur" ]
, pre [] [ text <| Decode.errorToString decodeError ]
]
]
}


notFound : Html msg
notFound =
Expand Down

0 comments on commit 2601218

Please sign in to comment.