docspell/modules/webapp/src/main/elm/App/Update.elm
Eike Kettner dd935454c9 First version of new ui based on tailwind
This drops fomantic-ui as css toolkit and introduces tailwindcss. With
tailwind there are no predefined components, but it's very easy to
create those. So customizing the look&feel is much simpler, most of
the time no additional css is needed.

This requires a complete rewrite of the markup + styles. Luckily all
logic can be kept as is. The now old ui is not removed, it is still
available by using a request header `Docspell-Ui` with a value of `1`
for the old ui and `2` for the new ui.

Another addition is "dev mode", where docspell serves assets with a
no-cache header, to disable browser caching. This makes developing a
lot easier.
2021-02-14 01:46:13 +01:00

483 lines
13 KiB
Elm

module App.Update exposing
( initPage
, update
)
import Api
import App.Data exposing (..)
import Browser exposing (UrlRequest(..))
import Browser.Navigation as Nav
import Data.Flags
import Data.UiTheme
import Page exposing (Page(..))
import Page.CollectiveSettings.Data
import Page.CollectiveSettings.Update
import Page.Home.Data
import Page.Home.Update
import Page.ItemDetail.Data
import Page.ItemDetail.Update
import Page.Login.Data
import Page.Login.Update
import Page.ManageData.Data
import Page.ManageData.Update
import Page.NewInvite.Data
import Page.NewInvite.Update
import Page.Queue.Data
import Page.Queue.Update
import Page.Register.Data
import Page.Register.Update
import Page.Upload.Data
import Page.Upload.Update
import Page.UserSettings.Data
import Page.UserSettings.Update
import Ports
import Url
import Util.Maybe
import Util.Update
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
let
( m, c, s ) =
updateWithSub msg model
in
( { m | subs = s }, c )
updateWithSub : Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateWithSub msg model =
case msg of
ToggleSidebar ->
( { model | sidebarVisible = not model.sidebarVisible }, Cmd.none, Sub.none )
ToggleDarkMode ->
let
settings =
model.uiSettings
next =
Data.UiTheme.cycle settings.uiTheme
newSettings =
{ settings | uiTheme = next }
in
case model.flags.account of
Just _ ->
-- when authenticated, store it in settings only
-- once new settings arrive via a subscription,
-- the ui is updated. so it is also updated on
-- page refresh
( { model | userMenuOpen = False }
, Ports.storeUiSettings model.flags newSettings
, Sub.none
)
Nothing ->
-- when not logged in, simply set the theme
( { model | userMenuOpen = False }
, Ports.setUiTheme next
, Sub.none
)
HomeMsg lm ->
updateHome lm model
LoginMsg lm ->
updateLogin lm model
ManageDataMsg lm ->
updateManageData lm model
CollSettingsMsg m ->
updateCollSettings m model
UserSettingsMsg m ->
updateUserSettings m model
QueueMsg m ->
updateQueue m model
RegisterMsg m ->
updateRegister m model
UploadMsg m ->
updateUpload m model
NewInviteMsg m ->
updateNewInvite m model
ItemDetailMsg m ->
updateItemDetail m model
VersionResp (Ok info) ->
( { model | version = info }, Cmd.none, Sub.none )
VersionResp (Err _) ->
( model, Cmd.none, Sub.none )
Logout ->
( model
, Cmd.batch
[ Api.logout model.flags LogoutResp
, Ports.removeAccount ()
]
, Sub.none
)
LogoutResp _ ->
( { model | loginModel = Page.Login.Data.emptyModel }
, Page.goto (LoginPage Nothing)
, Sub.none
)
SessionCheckResp res ->
case res of
Ok lr ->
let
newFlags =
if lr.success then
Data.Flags.withAccount model.flags lr
else
Data.Flags.withoutAccount model.flags
command =
if lr.success then
Cmd.batch
[ Api.refreshSession newFlags SessionCheckResp
, Ports.setAccount lr
, case model.flags.account of
Just _ ->
Cmd.none
Nothing ->
Page.goto model.page
]
else
Cmd.batch
[ Ports.removeAccount ()
, case model.page of
LoginPage _ ->
Cmd.none
_ ->
Page.goto (Page.loginPage model.page)
]
in
( { model | flags = newFlags }, command, Sub.none )
Err _ ->
( model
, Cmd.batch
[ Ports.removeAccount ()
, case model.page of
LoginPage _ ->
Cmd.none
_ ->
Page.goto (Page.loginPage model.page)
]
, Sub.none
)
NavRequest req ->
case req of
Internal url ->
let
isCurrent =
Page.fromUrl url
|> Maybe.map (\p -> p == model.page)
|> Maybe.withDefault True
in
( model
, if isCurrent then
Cmd.none
else
Nav.pushUrl model.key (Url.toString url)
, Sub.none
)
External url ->
( model
, Nav.load url
, Sub.none
)
NavChange url ->
let
page =
Page.fromUrl url
|> Maybe.withDefault (defaultPage model.flags)
( m, c, s ) =
initPage model page
in
( { m | page = page }, c, s )
ToggleNavMenu ->
( { model
| navMenuOpen = not model.navMenuOpen
, userMenuOpen =
if not model.navMenuOpen then
False
else
model.userMenuOpen
}
, Cmd.none
, Sub.none
)
ToggleUserMenu ->
( { model
| userMenuOpen = not model.userMenuOpen
, navMenuOpen =
if not model.userMenuOpen then
False
else
model.navMenuOpen
}
, Cmd.none
, Sub.none
)
GetUiSettings settings ->
let
setTheme =
Ports.setUiTheme settings.uiTheme
in
Util.Update.andThen2
[ \m ->
( { m | sidebarVisible = settings.sideMenuVisible }
, setTheme
, Sub.none
)
, updateUserSettings Page.UserSettings.Data.UpdateSettings
, updateHome Page.Home.Data.UiSettingsUpdated
, updateItemDetail Page.ItemDetail.Data.UiSettingsUpdated
]
{ model | uiSettings = settings }
updateItemDetail : Page.ItemDetail.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateItemDetail lmsg model =
let
inav =
Page.Home.Data.itemNav model.itemDetailModel.detail.item.id model.homeModel
result =
Page.ItemDetail.Update.update
model.key
model.flags
inav
model.uiSettings
lmsg
model.itemDetailModel
model_ =
{ model
| itemDetailModel = result.model
}
( hm, hc, hs ) =
updateHome (Page.Home.Data.SetLinkTarget result.linkTarget) model_
in
( hm
, Cmd.batch [ Cmd.map ItemDetailMsg result.cmd, hc ]
, Sub.batch [ Sub.map ItemDetailMsg result.sub, hs ]
)
updateNewInvite : Page.NewInvite.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateNewInvite lmsg model =
let
( lm, lc ) =
Page.NewInvite.Update.update model.flags lmsg model.newInviteModel
in
( { model | newInviteModel = lm }
, Cmd.map NewInviteMsg lc
, Sub.none
)
updateUpload : Page.Upload.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateUpload lmsg model =
let
( lm, lc, ls ) =
Page.Upload.Update.update
(Page.uploadId model.page)
model.flags
lmsg
model.uploadModel
in
( { model | uploadModel = lm }
, Cmd.map UploadMsg lc
, Sub.map UploadMsg ls
)
updateRegister : Page.Register.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateRegister lmsg model =
let
( lm, lc ) =
Page.Register.Update.update model.flags lmsg model.registerModel
in
( { model | registerModel = lm }
, Cmd.map RegisterMsg lc
, Sub.none
)
updateQueue : Page.Queue.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateQueue lmsg model =
let
( lm, lc ) =
Page.Queue.Update.update model.flags lmsg model.queueModel
in
( { model | queueModel = lm }
, Cmd.map QueueMsg lc
, Sub.none
)
updateUserSettings : Page.UserSettings.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateUserSettings lmsg model =
let
( lm, lc, ls ) =
Page.UserSettings.Update.update model.flags model.uiSettings lmsg model.userSettingsModel
in
( { model
| userSettingsModel = lm
}
, Cmd.map UserSettingsMsg lc
, Sub.map UserSettingsMsg ls
)
updateCollSettings : Page.CollectiveSettings.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateCollSettings lmsg model =
let
( lm, lc ) =
Page.CollectiveSettings.Update.update model.flags
lmsg
model.collSettingsModel
in
( { model | collSettingsModel = lm }
, Cmd.map CollSettingsMsg lc
, Sub.none
)
updateLogin : Page.Login.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateLogin lmsg model =
let
( lm, lc, ar ) =
Page.Login.Update.update (Page.loginPageReferrer model.page)
model.flags
lmsg
model.loginModel
newFlags =
Maybe.map (Data.Flags.withAccount model.flags) ar
|> Maybe.withDefault model.flags
in
( { model | loginModel = lm, flags = newFlags }
, Cmd.map LoginMsg lc
, Sub.none
)
updateHome : Page.Home.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateHome lmsg model =
let
mid =
case model.page of
HomePage ->
Util.Maybe.fromString model.itemDetailModel.detail.item.id
_ ->
Nothing
( lm, lc, ls ) =
Page.Home.Update.update mid model.key model.flags model.uiSettings lmsg model.homeModel
in
( { model
| homeModel = lm
}
, Cmd.map HomeMsg lc
, Sub.map HomeMsg ls
)
updateManageData : Page.ManageData.Data.Msg -> Model -> ( Model, Cmd Msg, Sub Msg )
updateManageData lmsg model =
let
( lm, lc ) =
Page.ManageData.Update.update model.flags lmsg model.manageDataModel
in
( { model | manageDataModel = lm }
, Cmd.map ManageDataMsg lc
, Sub.none
)
initPage : Model -> Page -> ( Model, Cmd Msg, Sub Msg )
initPage model_ page =
let
model =
{ model_ | page = page }
in
case page of
HomePage ->
Util.Update.andThen2
[ updateHome Page.Home.Data.Init
, updateQueue Page.Queue.Data.StopRefresh
]
model
LoginPage _ ->
updateQueue Page.Queue.Data.StopRefresh model
ManageDataPage ->
updateQueue Page.Queue.Data.StopRefresh model
CollectiveSettingPage ->
Util.Update.andThen2
[ updateQueue Page.Queue.Data.StopRefresh
, updateCollSettings Page.CollectiveSettings.Data.Init
]
model
UserSettingPage ->
Util.Update.andThen2
[ updateQueue Page.Queue.Data.StopRefresh
]
model
QueuePage ->
updateQueue Page.Queue.Data.Init model
RegisterPage ->
updateQueue Page.Queue.Data.StopRefresh model
UploadPage _ ->
Util.Update.andThen2
[ updateQueue Page.Queue.Data.StopRefresh
, updateUpload Page.Upload.Data.Clear
]
model
NewInvitePage ->
updateQueue Page.Queue.Data.StopRefresh model
ItemDetailPage id ->
Util.Update.andThen2
[ updateItemDetail (Page.ItemDetail.Data.Init id)
, updateQueue Page.Queue.Data.StopRefresh
]
model