diff --git a/modules/backend/src/main/scala/docspell/backend/ops/OClientSettings.scala b/modules/backend/src/main/scala/docspell/backend/ops/OClientSettings.scala index 4d2d71a2..560e4db4 100644 --- a/modules/backend/src/main/scala/docspell/backend/ops/OClientSettings.scala +++ b/modules/backend/src/main/scala/docspell/backend/ops/OClientSettings.scala @@ -6,6 +6,7 @@ package docspell.backend.ops +import cats.Semigroup import cats.data.OptionT import cats.effect.{Async, Resource} import cats.implicits._ @@ -32,6 +33,7 @@ trait OClientSettings[F[_]] { account: AccountId ): F[Option[RClientSettingsCollective]] + def loadMerged(clientId: Ident, account: AccountId): F[Option[Json]] } object OClientSettings { @@ -108,5 +110,14 @@ object OClientSettings { data <- OptionT(store.transact(RClientSettingsUser.find(clientId, userId))) } yield data).value + def loadMerged(clientId: Ident, account: AccountId) = + for { + collData <- loadCollective(clientId, account) + userData <- loadUser(clientId, account) + mergedData = collData.map(_.settingsData) |+| userData.map(_.settingsData) + } yield mergedData + + implicit def jsonSemigroup: Semigroup[Json] = + Semigroup.instance((a1, a2) => a1.deepMerge(a2)) }) } diff --git a/modules/backend/src/main/scala/docspell/backend/ops/OShare.scala b/modules/backend/src/main/scala/docspell/backend/ops/OShare.scala index cd0bac69..75bdc27a 100644 --- a/modules/backend/src/main/scala/docspell/backend/ops/OShare.scala +++ b/modules/backend/src/main/scala/docspell/backend/ops/OShare.scala @@ -48,6 +48,8 @@ trait OShare[F[_]] { // --- + def findActiveById(id: Ident): OptionT[F, ShareData] + /** Verifies the given id and password and returns a authorization token on success. */ def verify(key: ByteVector)(id: Ident, password: Option[Password]): F[VerifyResult] @@ -277,6 +279,9 @@ object OShare { VerifyResult.invalidToken.pure[F] } + def findActiveById(id: Ident): OptionT[F, ShareData] = + RShare.findCurrentActive(id).mapK(store.transform).map(ShareData.tupled) + def findShareQuery(id: Ident): OptionT[F, ShareQuery] = RShare .findCurrentActive(id) diff --git a/modules/restapi/src/main/resources/docspell-openapi.yml b/modules/restapi/src/main/resources/docspell-openapi.yml index c585b147..f6dc38ef 100644 --- a/modules/restapi/src/main/resources/docspell-openapi.yml +++ b/modules/restapi/src/main/resources/docspell-openapi.yml @@ -2304,7 +2304,7 @@ paths: /share/attachment/{id}/preview: head: operationId: "share-attach-check-preview" - tags: [ Attachment ] + tags: [ Share ] summary: Get the headers to a preview image of an attachment file. description: | Checks if an image file showing a preview of the attachment is @@ -2320,7 +2320,7 @@ paths: description: NotFound get: operationId: "share-attach-get-preview" - tags: [ Attachment ] + tags: [ Share ] summary: Get a preview image of an attachment file. description: | Gets a image file showing a preview of the attachment. Usually @@ -2347,6 +2347,31 @@ paths: schema: type: string format: binary + /share/clientSettings/{clientId}: + parameters: + - $ref: "#/components/parameters/clientId" + get: + operationId: "share-clientsettings-get" + tags: [ Share ] + summary: Return the client settings of current user + description: | + Returns the settings for the share. This is the settings of + the collective that belongs to the share. + + The `clientId` is an identifier to a client application. It + returns a JSON structure. The server doesn't care about the + actual data, since it is meant to be interpreted by clients. + security: + - shareTokenHeader: [] + responses: + 422: + description: BadRequest + 200: + description: Ok + content: + application/json: + schema: {} + /admin/user/resetPassword: post: diff --git a/modules/restserver/src/main/scala/docspell/restserver/RestServer.scala b/modules/restserver/src/main/scala/docspell/restserver/RestServer.scala index dd36286e..2d85a4f9 100644 --- a/modules/restserver/src/main/scala/docspell/restserver/RestServer.scala +++ b/modules/restserver/src/main/scala/docspell/restserver/RestServer.scala @@ -213,7 +213,8 @@ object RestServer { Router( "search" -> ShareSearchRoutes(restApp.backend, cfg, token), "attachment" -> ShareAttachmentRoutes(restApp.backend, token), - "item" -> ShareItemRoutes(restApp.backend, token) + "item" -> ShareItemRoutes(restApp.backend, token), + "clientSettings" -> ClientSettingsRoutes.share(restApp.backend, token) ) def redirectTo[F[_]: Async](path: String): HttpRoutes[F] = { diff --git a/modules/restserver/src/main/scala/docspell/restserver/routes/ClientSettingsRoutes.scala b/modules/restserver/src/main/scala/docspell/restserver/routes/ClientSettingsRoutes.scala index aef0b386..96dad4b4 100644 --- a/modules/restserver/src/main/scala/docspell/restserver/routes/ClientSettingsRoutes.scala +++ b/modules/restserver/src/main/scala/docspell/restserver/routes/ClientSettingsRoutes.scala @@ -6,12 +6,12 @@ package docspell.restserver.routes +import cats.data.OptionT import cats.effect._ import cats.implicits._ -import cats.kernel.Semigroup import docspell.backend.BackendApp -import docspell.backend.auth.AuthToken +import docspell.backend.auth.{AuthToken, ShareToken} import docspell.common._ import docspell.restapi.model._ @@ -23,6 +23,28 @@ import org.http4s.dsl.Http4sDsl object ClientSettingsRoutes { + def share[F[_]: Async]( + backend: BackendApp[F], + token: ShareToken + ): HttpRoutes[F] = { + val logger = Logger.log4s[F](org.log4s.getLogger) + + val dsl = new Http4sDsl[F] {} + import dsl._ + + HttpRoutes.of { case GET -> Root / Ident(clientId) => + (for { + _ <- OptionT.liftF(logger.debug(s"Get client settings for share ${token.id}")) + share <- backend.share.findActiveById(token.id) + sett <- OptionT( + backend.clientSettings.loadCollective(clientId, share.user.accountId) + ) + res <- OptionT.liftF(Ok(sett.settingsData)) + } yield res) + .getOrElseF(Ok(Map.empty[String, String])) + } + } + def apply[F[_]: Async](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ @@ -30,14 +52,10 @@ object ClientSettingsRoutes { HttpRoutes.of { case GET -> Root / Ident(clientId) => for { - collData <- backend.clientSettings.loadCollective(clientId, user.account) - userData <- backend.clientSettings.loadUser(clientId, user.account) - - mergedData = collData.map(_.settingsData) |+| userData.map(_.settingsData) - + mergedData <- backend.clientSettings.loadMerged(clientId, user.account) res <- mergedData match { case Some(j) => Ok(j) - case None => NotFound() + case None => Ok(Map.empty[String, String]) } } yield res @@ -96,7 +114,4 @@ object ClientSettingsRoutes { } yield res } } - - implicit def jsonSemigroup: Semigroup[Json] = - Semigroup.instance((a1, a2) => a1.deepMerge(a2)) } diff --git a/modules/webapp/src/main/elm/Api.elm b/modules/webapp/src/main/elm/Api.elm index 5a5cff99..9489e8aa 100644 --- a/modules/webapp/src/main/elm/Api.elm +++ b/modules/webapp/src/main/elm/Api.elm @@ -22,6 +22,7 @@ module Api exposing , changeFolderName , changePassword , checkCalEvent + , clientSettingsShare , confirmMultiple , confirmOtp , createChannel @@ -64,6 +65,7 @@ module Api exposing , getChannels , getChannelsIgnoreError , getClientSettings + , getClientSettingsRaw , getCollective , getCollectiveSettings , getContacts @@ -136,6 +138,7 @@ module Api exposing , restoreItem , sampleEvent , saveClientSettings + , saveUserClientSettingsBy , searchShare , searchShareStats , sendMail @@ -296,7 +299,7 @@ import Data.OrganizationOrder exposing (OrganizationOrder) import Data.PersonOrder exposing (PersonOrder) import Data.Priority exposing (Priority) import Data.TagOrder exposing (TagOrder) -import Data.UiSettings exposing (UiSettings) +import Data.UiSettings exposing (StoredUiSettings, UiSettings) import File exposing (File) import Http import Json.Decode as JsonDecode @@ -2335,6 +2338,13 @@ getItemProposals flags item receive = --- Client Settings +uiSettingsPath : AccountScope -> String +uiSettingsPath scope = + Data.AccountScope.fold "/api/v1/sec/clientSettings/user/webClient" + "/api/v1/sec/clientSettings/collective/webClient" + scope + + getClientSettings : Flags -> (Result Http.Error UiSettings -> msg) -> Cmd msg getClientSettings flags receive = let @@ -2346,29 +2356,91 @@ getClientSettings flags receive = Data.UiSettings.storedUiSettingsDecoder in Http2.authGet - { url = flags.config.baseUrl ++ "/api/v1/sec/clientSettings/user/webClient" + { url = flags.config.baseUrl ++ "/api/v1/sec/clientSettings/webClient" , account = getAccount flags , expect = Http.expectJson receive decoder } -saveClientSettings : Flags -> UiSettings -> (Result Http.Error BasicResult -> msg) -> Cmd msg -saveClientSettings flags settings receive = +getClientSettingsTaskFor : Flags -> AccountScope -> Task.Task Http.Error StoredUiSettings +getClientSettingsTaskFor flags scope = let - storedSettings = - Data.UiSettings.toStoredUiSettings settings - - encode = - Data.UiSettings.storedUiSettingsEncode storedSettings + path = + uiSettingsPath scope in - Http2.authPut - { url = flags.config.baseUrl ++ "/api/v1/sec/clientSettings/user/webClient" + Http2.authTask + { method = "GET" + , url = flags.config.baseUrl ++ path , account = getAccount flags - , body = Http.jsonBody encode - , expect = Http.expectJson receive Api.Model.BasicResult.decoder + , body = Http.emptyBody + , resolver = Http2.jsonResolver Data.UiSettings.storedUiSettingsDecoder + , headers = [] + , timeout = Nothing } +getClientSettingsRaw : Flags -> (Result Http.Error ( StoredUiSettings, StoredUiSettings ) -> msg) -> Cmd msg +getClientSettingsRaw flags receive = + let + coll = + getClientSettingsTaskFor flags Data.AccountScope.Collective + + user = + getClientSettingsTaskFor flags Data.AccountScope.User + in + Task.map2 Tuple.pair coll user |> Task.attempt receive + + +saveClientSettingsTask : + Flags + -> StoredUiSettings + -> AccountScope + -> Task.Task Http.Error BasicResult +saveClientSettingsTask flags settings scope = + let + encoded = + Data.UiSettings.storedUiSettingsEncode settings + + path = + uiSettingsPath scope + in + Http2.authTask + { method = "PUT" + , url = flags.config.baseUrl ++ path + , account = getAccount flags + , body = Http.jsonBody encoded + , resolver = Http2.jsonResolver Api.Model.BasicResult.decoder + , headers = [] + , timeout = Nothing + } + + +saveClientSettings : + Flags + -> StoredUiSettings + -> AccountScope + -> (Result Http.Error BasicResult -> msg) + -> Cmd msg +saveClientSettings flags settings scope receive = + saveClientSettingsTask flags settings scope |> Task.attempt receive + + +saveUserClientSettingsBy : + Flags + -> (StoredUiSettings -> StoredUiSettings) + -> (Result Http.Error BasicResult -> msg) + -> Cmd msg +saveUserClientSettingsBy flags modify receive = + let + readTask = + getClientSettingsTaskFor flags Data.AccountScope.User + + save s = + saveClientSettingsTask flags s Data.AccountScope.User + in + Task.andThen (modify >> save) readTask |> Task.attempt receive + + --- Dashboards @@ -2749,6 +2821,23 @@ itemDetailShare flags token itemId receive = } +clientSettingsShare : Flags -> String -> (Result Http.Error UiSettings -> msg) -> Cmd msg +clientSettingsShare flags token receive = + let + defaults = + Data.UiSettings.defaults + + decoder = + JsonDecode.map (\s -> Data.UiSettings.merge s defaults) + Data.UiSettings.storedUiSettingsDecoder + in + Http2.shareGet + { url = flags.config.baseUrl ++ "/api/v1/share/clientSettings/webClient" + , token = token + , expect = Http.expectJson receive decoder + } + + shareSendMail : Flags -> { conn : String, mail : SimpleShareMail } diff --git a/modules/webapp/src/main/elm/App/Data.elm b/modules/webapp/src/main/elm/App/Data.elm index 0facd89b..ca2b362c 100644 --- a/modules/webapp/src/main/elm/App/Data.elm +++ b/modules/webapp/src/main/elm/App/Data.elm @@ -18,18 +18,15 @@ import Api.Model.BasicResult exposing (BasicResult) import Api.Model.VersionInfo exposing (VersionInfo) import Browser exposing (UrlRequest) import Browser.Navigation exposing (Key) -import Data.Dashboard exposing (Dashboard) import Data.Flags exposing (Flags) import Data.ServerEvent exposing (ServerEvent) -import Data.UiSettings exposing (StoredUiSettings, UiSettings) +import Data.UiSettings exposing (UiSettings) import Data.UiTheme exposing (UiTheme) import Http -import Messages import Messages.UiLanguage exposing (UiLanguage) import Page exposing (Page(..)) import Page.CollectiveSettings.Data import Page.Dashboard.Data -import Page.Dashboard.DefaultDashboard import Page.ItemDetail.Data import Page.Login.Data import Page.ManageData.Data @@ -107,11 +104,7 @@ init key url flags_ settings = Page.Dashboard.Data.init flags searchViewMode = - if settings.searchMenuVisible then - Page.Search.Data.SearchView - - else - Page.Search.Data.SimpleView + Page.Search.Data.SearchView in ( { flags = flags , key = key @@ -204,8 +197,7 @@ type Msg | ToggleDarkMode | ToggleLangMenu | SetLanguage UiLanguage - | ClientSettingsSaveResp UiSettings (Result Http.Error BasicResult) - | ReceiveBrowserSettings StoredUiSettings + | ClientSettingsSaveResp (Result Http.Error BasicResult) | ReceiveWsMessage (Result String ServerEvent) | ToggleShowNewItemsArrived diff --git a/modules/webapp/src/main/elm/App/Update.elm b/modules/webapp/src/main/elm/App/Update.elm index 268e05cf..48e2621d 100644 --- a/modules/webapp/src/main/elm/App/Update.elm +++ b/modules/webapp/src/main/elm/App/Update.elm @@ -14,6 +14,7 @@ import Api import App.Data exposing (..) import Browser exposing (UrlRequest(..)) import Browser.Navigation as Nav +import Data.AppEvent exposing (AppEvent(..)) import Data.Flags import Data.ServerEvent exposing (ServerEvent(..)) import Data.UiSettings exposing (UiSettings) @@ -81,15 +82,15 @@ updateWithSub msg model = next = Data.UiTheme.cycle settings.uiTheme - newSettings = - { settings | uiTheme = next } + newSettings s = + { s | uiTheme = Just (Data.UiTheme.toString next) } in -- when authenticated, store it in settings only -- once new settings are successfully saved (the -- response is arrived), the ui is updated. so it -- is also updated on page refresh ( { model | userMenuOpen = False } - , Api.saveClientSettings model.flags newSettings (ClientSettingsSaveResp newSettings) + , Api.saveUserClientSettingsBy model.flags newSettings ClientSettingsSaveResp , Sub.none ) @@ -104,14 +105,14 @@ updateWithSub msg model = , Sub.none ) - ClientSettingsSaveResp settings (Ok res) -> + ClientSettingsSaveResp (Ok res) -> if res.success then - applyClientSettings texts model settings + ( model, Api.getClientSettings model.flags GetUiSettings, Sub.none ) else ( model, Cmd.none, Sub.none ) - ClientSettingsSaveResp _ (Err _) -> + ClientSettingsSaveResp (Err _) -> ( model, Cmd.none, Sub.none ) ToggleLangMenu -> @@ -307,13 +308,6 @@ updateWithSub msg model = GetUiSettings (Err _) -> ( model, Cmd.none, Sub.none ) - ReceiveBrowserSettings sett -> - let - lm = - Page.UserSettings.Data.ReceiveBrowserSettings sett - in - updateUserSettings texts lm model - ReceiveWsMessage data -> case data of Ok (JobDone task) -> @@ -342,7 +336,7 @@ updateWithSub msg model = Ok (JobsWaiting n) -> ( { model | jobsWaiting = max 0 n }, Cmd.none, Sub.none ) - Err err -> + Err _ -> ( model, Cmd.none, Sub.none ) ToggleShowNewItemsArrived -> @@ -368,7 +362,6 @@ applyClientSettings texts model settings = , Sub.none ) , updateDashboard texts Page.Dashboard.Data.reloadUiSettings - , updateUserSettings texts Page.UserSettings.Data.UpdateSettings , updateSearch texts Page.Search.Data.UiSettingsUpdated , updateItemDetail texts Page.ItemDetail.Data.UiSettingsUpdated ] @@ -524,22 +517,21 @@ updateUserSettings texts lmsg model = model_ = { model | userSettingsModel = result.model } - ( lm2, lc2, s2 ) = - case result.newSettings of - Just sett -> - applyClientSettings texts model_ sett + lc = + case result.appEvent of + AppReloadUiSettings -> + Api.getClientSettings model.flags GetUiSettings - Nothing -> - ( model_, Cmd.none, Sub.none ) + AppNothing -> + Cmd.none in - ( lm2 + ( model_ , Cmd.batch [ Cmd.map UserSettingsMsg result.cmd - , lc2 + , lc ] , Sub.batch [ Sub.map UserSettingsMsg result.sub - , s2 ] ) @@ -595,22 +587,21 @@ updateSearch texts lmsg model = model_ = { model | searchModel = result.model } - ( lm, lc, ls ) = - case result.newSettings of - Just sett -> - applyClientSettings texts model_ sett + lc = + case result.appEvent of + AppReloadUiSettings -> + Api.getClientSettings model.flags GetUiSettings - Nothing -> - ( model_, Cmd.none, Sub.none ) + AppNothing -> + Cmd.none in - ( lm + ( model_ , Cmd.batch [ Cmd.map SearchMsg result.cmd , lc ] , Sub.batch [ Sub.map SearchMsg result.sub - , ls ] ) diff --git a/modules/webapp/src/main/elm/Comp/BoxQueryView.elm b/modules/webapp/src/main/elm/Comp/BoxQueryView.elm index c84bb9fa..574a8792 100644 --- a/modules/webapp/src/main/elm/Comp/BoxQueryView.elm +++ b/modules/webapp/src/main/elm/Comp/BoxQueryView.elm @@ -144,7 +144,12 @@ viewItemRow texts settings meta item = getColumns meta render col = - Comp.ItemColumnView.renderDiv texts.templateCtx settings col [ class "flex flex-row flex-wrap space-x-1" ] item + Comp.ItemColumnView.renderDiv + texts.templateCtx + settings + col + [ class "flex flex-row flex-wrap space-x-1 space-y-1" ] + item td1 = td [ class "py-2 px-1" ] @@ -158,7 +163,7 @@ viewItemRow texts settings meta item = tdRem index col = td - [ class "py-2 px-1" + [ class "py-1 px-1" , classList [ ( "hidden md:table-cell", index > 1 ) ] ] [ render col diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm index 6af8466d..8ec84d32 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm @@ -1411,7 +1411,7 @@ update key flags inav settings msg model = let model_ = { model - | menuOpen = settings.editMenuVisible + | menuOpen = settings.sideMenuVisible } in resultModel model_ diff --git a/modules/webapp/src/main/elm/Comp/MenuBar.elm b/modules/webapp/src/main/elm/Comp/MenuBar.elm index b5819ae2..825b9bcd 100644 --- a/modules/webapp/src/main/elm/Comp/MenuBar.elm +++ b/modules/webapp/src/main/elm/Comp/MenuBar.elm @@ -26,6 +26,7 @@ import Styles as S type Item msg = TextInput (TextInputData msg) | Checkbox (CheckboxData msg) + | RadioButton (CheckboxData msg) | PrimaryButton (ButtonData msg) | SecondaryButton (ButtonData msg) | DeleteButton (ButtonData msg) @@ -119,7 +120,7 @@ view1 classes mb = (List.map viewItem mb.start) right = - div [ class "flex-grow flex-row flex justify-end space-x-2 w-full" ] + div [ class "flex-grow flex-row items-center flex justify-end space-x-2 w-full" ] (List.map viewItem mb.end) in div @@ -139,7 +140,10 @@ viewItem item = makeInput model Checkbox model -> - makeCheckbox model + makeCheckbox False model + + RadioButton model -> + makeCheckbox True model PrimaryButton model -> makeButton [ ( S.primaryButton, True ) ] model @@ -306,8 +310,8 @@ makeButton btnType model = (icon ++ label) -makeCheckbox : CheckboxData msg -> Html msg -makeCheckbox model = +makeCheckbox : Bool -> CheckboxData msg -> Html msg +makeCheckbox radio model = let withId list = if model.id == "" then @@ -315,6 +319,13 @@ makeCheckbox model = else id model.id :: list + + fold rd ck = + if radio then + rd + + else + ck in div [ class "" ] [ label @@ -323,10 +334,10 @@ makeCheckbox model = ] [ input (withId - [ type_ "checkbox" + [ type_ (fold "radio" "checkbox") , onCheck model.tagger , checked model.value - , class S.checkboxInput + , class (fold S.radioInput S.checkboxInput) ] ) [] diff --git a/modules/webapp/src/main/elm/Comp/UiSettingsForm.elm b/modules/webapp/src/main/elm/Comp/UiSettingsForm.elm index ecfb6781..87ef2f75 100644 --- a/modules/webapp/src/main/elm/Comp/UiSettingsForm.elm +++ b/modules/webapp/src/main/elm/Comp/UiSettingsForm.elm @@ -9,6 +9,8 @@ module Comp.UiSettingsForm exposing ( Model , Msg , init + , initData + , toggleAllTabs , update , view2 ) @@ -30,7 +32,7 @@ import Data.Flags exposing (Flags) import Data.ItemTemplate as IT exposing (ItemTemplate) import Data.Pdf exposing (PdfMode) import Data.TagOrder -import Data.UiSettings exposing (ItemPattern, Pos(..), UiSettings) +import Data.UiSettings exposing (ItemPattern, StoredUiSettings, UiSettings) import Dict exposing (Dict) import Html exposing (..) import Html.Attributes exposing (..) @@ -73,6 +75,7 @@ type alias Model = , uiLangModel : Comp.FixedDropdown.Model UiLanguage , uiLang : UiLanguage , openTabs : Set String + , defaults : UiSettings } @@ -111,61 +114,78 @@ updatePatternModel pm str = } -init : Flags -> UiSettings -> ( Model, Cmd Msg ) -init flags settings = - ( { itemSearchPageSize = Just settings.itemSearchPageSize - , searchPageSizeModel = - Comp.IntField.init - (Just 10) - (Just flags.config.maxPageSize) - False - , tagColors = settings.tagCategoryColors - , tagColorModel = - Comp.ColorTagger.init - [] - Data.Color.all - , pdfMode = settings.pdfMode - , pdfModeModel = Comp.FixedDropdown.init Data.Pdf.allModes - , itemSearchNoteLength = Just settings.itemSearchNoteLength - , searchNoteLengthModel = - Comp.IntField.init - (Just 0) - (Just flags.config.maxNoteLength) - False - , searchMenuFolderCount = Just settings.searchMenuFolderCount - , searchMenuFolderCountModel = - Comp.IntField.init - (Just 0) - (Just 2000) - False - , searchMenuTagCount = Just settings.searchMenuTagCount - , searchMenuTagCountModel = - Comp.IntField.init - (Just 0) - (Just 2000) - False - , searchMenuTagCatCount = Just settings.searchMenuTagCatCount - , searchMenuTagCatCountModel = - Comp.IntField.init - (Just 0) - (Just 2000) - False - , formFields = settings.formFields - , itemDetailShortcuts = settings.itemDetailShortcuts - , cardPreviewSize = settings.cardPreviewSize - , cardTitlePattern = initPatternModel settings.cardTitleTemplate - , cardSubtitlePattern = initPatternModel settings.cardSubtitleTemplate - , showPatternHelp = False - , searchStatsVisible = settings.searchStatsVisible - , sideMenuVisible = settings.sideMenuVisible - , powerSearchEnabled = settings.powerSearchEnabled - , uiLang = settings.uiLang - , uiLangModel = - Comp.FixedDropdown.init Messages.UiLanguage.all - , openTabs = Set.empty - } - , Api.getTags flags "" Data.TagOrder.NameAsc GetTagsResp - ) +initModel : Flags -> StoredUiSettings -> UiSettings -> Model +initModel flags storedSettings defaults = + let + settings = + Data.UiSettings.merge storedSettings defaults + in + { itemSearchPageSize = Just settings.itemSearchPageSize + , searchPageSizeModel = + Comp.IntField.init + (Just 10) + (Just flags.config.maxPageSize) + False + , tagColors = settings.tagCategoryColors + , tagColorModel = + Comp.ColorTagger.init + [] + Data.Color.all + , pdfMode = settings.pdfMode + , pdfModeModel = Comp.FixedDropdown.init Data.Pdf.allModes + , itemSearchNoteLength = Just settings.itemSearchNoteLength + , searchNoteLengthModel = + Comp.IntField.init + (Just 0) + (Just flags.config.maxNoteLength) + False + , searchMenuFolderCount = Just settings.searchMenuFolderCount + , searchMenuFolderCountModel = + Comp.IntField.init + (Just 0) + (Just 2000) + False + , searchMenuTagCount = Just settings.searchMenuTagCount + , searchMenuTagCountModel = + Comp.IntField.init + (Just 0) + (Just 2000) + False + , searchMenuTagCatCount = Just settings.searchMenuTagCatCount + , searchMenuTagCatCountModel = + Comp.IntField.init + (Just 0) + (Just 2000) + False + , formFields = settings.formFields + , itemDetailShortcuts = settings.itemDetailShortcuts + , cardPreviewSize = settings.cardPreviewSize + , cardTitlePattern = initPatternModel settings.cardTitleTemplate + , cardSubtitlePattern = initPatternModel settings.cardSubtitleTemplate + , showPatternHelp = False + , searchStatsVisible = settings.searchStatsVisible + , sideMenuVisible = settings.sideMenuVisible + , powerSearchEnabled = settings.powerSearchEnabled + , uiLang = settings.uiLang + , uiLangModel = + Comp.FixedDropdown.init Messages.UiLanguage.all + , openTabs = Set.empty + , defaults = defaults + } + + +init : Flags -> StoredUiSettings -> UiSettings -> ( Model, Cmd Msg ) +init flags storedSettings defaults = + ( initModel flags storedSettings defaults, Api.getTags flags "" Data.TagOrder.NameAsc GetTagsResp ) + + +initData : Flags -> StoredUiSettings -> UiSettings -> Model -> ( Model, Cmd Msg ) +initData flags storedSettings defaults model = + let + ( m, c ) = + init flags storedSettings defaults + in + ( { m | openTabs = model.openTabs }, c ) type Msg @@ -188,14 +208,61 @@ type Msg | TogglePowerSearch | UiLangMsg (Comp.FixedDropdown.Msg UiLanguage) | PdfModeMsg (Comp.FixedDropdown.Msg PdfMode) + | ToggleAllTabs + | ResetTab AkkordionTab + + +toggleAllTabs : Msg +toggleAllTabs = + ToggleAllTabs + + +type AkkordionTab + = GeneralTab + | SearchTab + | CardsTab + | SearchMenuTab + | DetailTab + | TagsTab + | FieldsTab + + +allTabs : List AkkordionTab +allTabs = + [ GeneralTab, SearchTab, CardsTab, SearchMenuTab, DetailTab, TagsTab, FieldsTab ] + + +akkordionTabName : AkkordionTab -> String +akkordionTabName tab = + case tab of + GeneralTab -> + "general" + + SearchTab -> + "search" + + CardsTab -> + "item-cards" + + SearchMenuTab -> + "search-menu" + + DetailTab -> + "item-detail" + + TagsTab -> + "tags" + + FieldsTab -> + "fields" --- Update -update : UiSettings -> Msg -> Model -> ( Model, Maybe UiSettings ) -update sett msg model = +update : Flags -> StoredUiSettings -> Msg -> Model -> ( Model, Maybe StoredUiSettings ) +update flags sett msg model = case msg of SearchPageSizeMsg lm -> let @@ -203,7 +270,7 @@ update sett msg model = Comp.IntField.update lm model.searchPageSizeModel nextSettings = - Maybe.map (\sz -> { sett | itemSearchPageSize = sz }) n + Maybe.map (\sz -> { sett | itemSearchPageSize = Just sz }) n model_ = { model @@ -219,7 +286,7 @@ update sett msg model = Comp.IntField.update lm model.searchNoteLengthModel nextSettings = - Maybe.map (\len -> { sett | itemSearchNoteLength = len }) n + Maybe.map (\len -> { sett | itemSearchNoteLength = Just len }) n model_ = { model @@ -235,7 +302,7 @@ update sett msg model = Comp.IntField.update lm model.searchMenuFolderCountModel nextSettings = - Maybe.map (\len -> { sett | searchMenuFolderCount = len }) n + Maybe.map (\len -> { sett | searchMenuFolderCount = Just len }) n model_ = { model @@ -251,7 +318,7 @@ update sett msg model = Comp.IntField.update lm model.searchMenuTagCountModel nextSettings = - Maybe.map (\len -> { sett | searchMenuTagCount = len }) n + Maybe.map (\len -> { sett | searchMenuTagCount = Just len }) n model_ = { model @@ -267,7 +334,7 @@ update sett msg model = Comp.IntField.update lm model.searchMenuTagCatCountModel nextSettings = - Maybe.map (\len -> { sett | searchMenuTagCatCount = len }) n + Maybe.map (\len -> { sett | searchMenuTagCatCount = Just len }) n model_ = { model @@ -282,8 +349,13 @@ update sett msg model = ( m_, d_ ) = Comp.ColorTagger.update lm model.tagColorModel + colors dict = + Dict.map (\_ -> Data.Color.toString) dict + |> Dict.toList + |> Just + nextSettings = - Maybe.map (\tc -> { sett | tagCategoryColors = tc }) d_ + Maybe.map (\tc -> { sett | tagCategoryColors = colors tc }) d_ model_ = { model @@ -316,7 +388,11 @@ update sett msg model = Comp.FieldListSelect.update lm model.formFields newSettings = - { sett | formFields = selected } + { sett + | formFields = + List.map Data.Fields.toString selected + |> Just + } in ( { model | formFields = selected } , if selected /= model.formFields then @@ -332,7 +408,7 @@ update sett msg model = not model.itemDetailShortcuts in ( { model | itemDetailShortcuts = flag } - , Just { sett | itemDetailShortcuts = flag } + , Just { sett | itemDetailShortcuts = Just flag } ) CardPreviewSizeMsg lm -> @@ -343,7 +419,13 @@ update sett msg model = newSettings = if next /= model.cardPreviewSize then - Just { sett | cardPreviewSize = next } + Just + { sett + | cardPreviewSize = + next + |> Data.BasicSize.asString + |> Just + } else Nothing @@ -361,14 +443,8 @@ update sett msg model = updatePatternModel pm str newSettings = - if pm_.pattern /= Just sett.cardTitleTemplate.pattern then - Just - { sett - | cardTitleTemplate = - ItemPattern - (Maybe.withDefault "" pm_.pattern) - pm_.current - } + if pm_.pattern /= sett.cardTitleTemplate then + Just { sett | cardTitleTemplate = pm_.pattern } else Nothing @@ -384,14 +460,8 @@ update sett msg model = updatePatternModel pm str newSettings = - if pm_.pattern /= Just sett.cardSubtitleTemplate.pattern then - Just - { sett - | cardSubtitleTemplate = - ItemPattern - (Maybe.withDefault "" pm_.pattern) - pm_.current - } + if pm_.pattern /= sett.cardSubtitleTemplate then + Just { sett | cardSubtitleTemplate = pm_.pattern } else Nothing @@ -407,9 +477,21 @@ update sett msg model = not model.searchStatsVisible in ( { model | searchStatsVisible = flag } - , Just { sett | searchStatsVisible = flag } + , Just { sett | searchStatsVisible = Just flag } ) + ToggleAllTabs -> + let + tabs = + if Set.isEmpty model.openTabs then + List.map akkordionTabName allTabs + |> Set.fromList + + else + Set.empty + in + ( { model | openTabs = tabs }, Nothing ) + ToggleAkkordionTab name -> let tabs = @@ -429,7 +511,7 @@ update sett msg model = not model.sideMenuVisible in ( { model | sideMenuVisible = next } - , Just { sett | sideMenuVisible = next } + , Just { sett | sideMenuVisible = Just next } ) TogglePowerSearch -> @@ -438,7 +520,7 @@ update sett msg model = not model.powerSearchEnabled in ( { model | powerSearchEnabled = next } - , Just { sett | powerSearchEnabled = next } + , Just { sett | powerSearchEnabled = Just next } ) UiLangMsg lm -> @@ -454,7 +536,7 @@ update sett msg model = Nothing else - Just { sett | uiLang = newLang } + Just { sett | uiLang = Just (Messages.toIso2 newLang) } ) PdfModeMsg lm -> @@ -470,9 +552,52 @@ update sett msg model = Nothing else - Just { sett | pdfMode = newMode } + Just { sett | pdfMode = Just (Data.Pdf.asString newMode) } ) + ResetTab tab -> + let + newSettings = + case tab of + GeneralTab -> + { sett | uiLang = Nothing, sideMenuVisible = Nothing } + + SearchTab -> + { sett + | itemSearchPageSize = Nothing + , searchStatsVisible = Nothing + , powerSearchEnabled = Nothing + } + + CardsTab -> + { sett + | itemSearchNoteLength = Nothing + , cardPreviewSize = Nothing + , cardTitleTemplate = Nothing + , cardSubtitleTemplate = Nothing + } + + SearchMenuTab -> + { sett + | searchMenuTagCount = Nothing + , searchMenuTagCatCount = Nothing + , searchMenuFolderCount = Nothing + } + + DetailTab -> + { sett | pdfMode = Nothing, itemDetailShortcuts = Nothing } + + TagsTab -> + { sett | tagCategoryColors = Nothing } + + FieldsTab -> + { sett | formFields = Nothing } + + nm = + initModel flags newSettings model.defaults + in + ( { nm | openTabs = model.openTabs }, Just newSettings ) + --- View2 @@ -495,7 +620,7 @@ tagColorViewOpts2 texts = } -view2 : Texts -> Flags -> UiSettings -> Model -> Html Msg +view2 : Texts -> Flags -> StoredUiSettings -> Model -> Html Msg view2 texts flags settings model = let state tab = @@ -517,7 +642,7 @@ view2 texts flags settings model = ] -settingFormTabs : Texts -> Flags -> UiSettings -> Model -> List (Comp.Tabs.Tab Msg) +settingFormTabs : Texts -> Flags -> StoredUiSettings -> Model -> List (Comp.Tabs.Tab Msg) settingFormTabs texts flags _ model = let langCfg = @@ -533,10 +658,21 @@ settingFormTabs texts flags _ model = , style = DS.mainStyle , selectPlaceholder = texts.basics.selectPlaceholder } + + resetLink tab = + a + [ href "#" + , class S.link + , class "text-sm" + , onClick (ResetTab tab) + ] + [ i [ class "fa fa-eraser mr-1" ] [] + , text texts.resetLabel + ] in - [ { name = "general" + [ { name = akkordionTabName GeneralTab , title = texts.general - , titleRight = [] + , titleRight = [ resetLink GeneralTab ] , info = Nothing , body = [ div [ class "mb-4 " ] @@ -560,9 +696,9 @@ settingFormTabs texts flags _ model = ] ] } - , { name = "item-search" + , { name = akkordionTabName SearchTab , title = texts.itemSearch - , titleRight = [] + , titleRight = [ resetLink SearchTab ] , info = Nothing , body = [ Html.map SearchPageSizeMsg @@ -594,9 +730,9 @@ settingFormTabs texts flags _ model = ] ] } - , { name = "item-cards" + , { name = akkordionTabName CardsTab , title = texts.itemCards - , titleRight = [] + , titleRight = [ resetLink CardsTab ] , info = Nothing , body = [ Html.map NoteLengthMsg @@ -666,9 +802,9 @@ settingFormTabs texts flags _ model = texts.templateHelpMessage ] } - , { name = "search-menu" + , { name = akkordionTabName SearchMenuTab , title = texts.searchMenu - , titleRight = [] + , titleRight = [ resetLink SearchMenuTab ] , info = Nothing , body = [ Html.map SearchMenuTagMsg @@ -700,9 +836,9 @@ settingFormTabs texts flags _ model = ) ] } - , { name = "item-detail" + , { name = akkordionTabName DetailTab , title = texts.itemDetail - , titleRight = [] + , titleRight = [ resetLink DetailTab ] , info = Nothing , body = [ div [ class "mb-4" ] @@ -726,9 +862,9 @@ settingFormTabs texts flags _ model = ] ] } - , { name = "tag-category-colors" + , { name = akkordionTabName TagsTab , title = texts.tagCategoryColors - , titleRight = [] + , titleRight = [ resetLink TagsTab ] , info = Nothing , body = [ Html.map TagColorMsg @@ -739,9 +875,9 @@ settingFormTabs texts flags _ model = ) ] } - , { name = "fields" + , { name = akkordionTabName FieldsTab , title = texts.fields - , titleRight = [] + , titleRight = [ resetLink FieldsTab ] , info = Nothing , body = [ span [ class "opacity-50 text-sm" ] diff --git a/modules/webapp/src/main/elm/Comp/UiSettingsManage.elm b/modules/webapp/src/main/elm/Comp/UiSettingsManage.elm index c1a96ecc..26757edb 100644 --- a/modules/webapp/src/main/elm/Comp/UiSettingsManage.elm +++ b/modules/webapp/src/main/elm/Comp/UiSettingsManage.elm @@ -16,26 +16,44 @@ module Comp.UiSettingsManage exposing import Api import Api.Model.BasicResult exposing (BasicResult) +import Comp.Basic import Comp.MenuBar as MB import Comp.UiSettingsForm -import Comp.UiSettingsMigrate +import Data.AccountScope exposing (AccountScope) +import Data.AppEvent exposing (AppEvent(..)) import Data.Flags exposing (Flags) import Data.UiSettings exposing (StoredUiSettings, UiSettings) import Html exposing (..) import Html.Attributes exposing (..) import Http import Messages.Comp.UiSettingsManage exposing (Texts) +import Page.Search.Data exposing (Msg(..)) +import Process import Styles as S +import Task type alias Model = - { formModel : Comp.UiSettingsForm.Model - , settings : Maybe UiSettings + { formModel : FormView , formResult : FormResult - , settingsMigrate : Comp.UiSettingsMigrate.Model + , formData : Maybe FormData } +type alias FormData = + { userSettings : StoredUiSettings + , userModel : Comp.UiSettingsForm.Model + , collSettings : StoredUiSettings + , collModel : Comp.UiSettingsForm.Model + } + + +type FormView + = ViewLoading + | ViewUser + | ViewCollective + + type FormResult = FormInit | FormUnchanged @@ -45,35 +63,40 @@ type FormResult type Msg - = UiSettingsFormMsg Comp.UiSettingsForm.Msg - | UiSettingsMigrateMsg Comp.UiSettingsMigrate.Msg + = UiFormMsg AccountScope Comp.UiSettingsForm.Msg | Submit - | UpdateSettings - | SaveSettingsResp UiSettings (Result Http.Error BasicResult) - | ReceiveBrowserSettings StoredUiSettings + | SaveSettingsResp (Result Http.Error BasicResult) + | ReceiveServerSettings (Result Http.Error ( StoredUiSettings, StoredUiSettings )) + | ToggleExpandCollapse + | SwitchForm AccountScope + | ResetFormState -init : Flags -> UiSettings -> ( Model, Cmd Msg ) -init flags settings = - let - ( fm, fc ) = - Comp.UiSettingsForm.init flags settings - - ( mm, mc ) = - Comp.UiSettingsMigrate.init flags - in - ( { formModel = fm - , settings = Nothing +init : Flags -> ( Model, Cmd Msg ) +init flags = + ( { formModel = ViewLoading + , formData = Nothing , formResult = FormInit - , settingsMigrate = mm } , Cmd.batch - [ Cmd.map UiSettingsFormMsg fc - , Cmd.map UiSettingsMigrateMsg mc + [ Api.getClientSettingsRaw flags ReceiveServerSettings ] ) +getViewScope : Model -> AccountScope +getViewScope model = + case model.formModel of + ViewCollective -> + Data.AccountScope.Collective + + ViewUser -> + Data.AccountScope.User + + _ -> + Data.AccountScope.User + + --- update @@ -82,108 +105,177 @@ type alias UpdateResult = { model : Model , cmd : Cmd Msg , sub : Sub Msg - , newSettings : Maybe UiSettings + , appEvent : AppEvent } +unit : Model -> UpdateResult +unit model = + UpdateResult model Cmd.none Sub.none AppNothing + + update : Flags -> UiSettings -> Msg -> Model -> UpdateResult update flags settings msg model = case msg of - UiSettingsFormMsg lm -> + UiFormMsg scope lm -> + case model.formData of + Nothing -> + unit model + + Just data -> + case scope of + Data.AccountScope.Collective -> + let + ( m_, sett ) = + Comp.UiSettingsForm.update flags data.collSettings lm data.collModel + in + unit + { model + | formData = + Just + { data + | collSettings = Maybe.withDefault data.collSettings sett + , collModel = m_ + } + } + + Data.AccountScope.User -> + let + ( m_, sett ) = + Comp.UiSettingsForm.update flags data.userSettings lm data.userModel + in + unit + { model + | formData = + Just + { data + | userSettings = Maybe.withDefault data.userSettings sett + , userModel = m_ + } + } + + Submit -> + case ( model.formModel, model.formData ) of + ( ViewCollective, Just data ) -> + { model = { model | formResult = FormInit } + , cmd = + Api.saveClientSettings flags + data.collSettings + Data.AccountScope.Collective + SaveSettingsResp + , sub = Sub.none + , appEvent = AppNothing + } + + ( ViewUser, Just data ) -> + { model = { model | formResult = FormInit } + , cmd = + Api.saveClientSettings flags + data.userSettings + Data.AccountScope.User + SaveSettingsResp + , sub = Sub.none + , appEvent = AppNothing + } + + _ -> + unit model + + SaveSettingsResp (Ok res) -> + case ( res.success, model.formData ) of + ( True, Just data ) -> + let + result = + update flags + settings + (ReceiveServerSettings (Ok ( data.collSettings, data.userSettings ))) + { model | formResult = FormSaved } + + cmd = + Process.sleep 2000 + |> Task.perform (\_ -> ResetFormState) + in + { result | appEvent = AppReloadUiSettings, cmd = Cmd.batch [ cmd, result.cmd ] } + + _ -> + unit { model | formResult = FormUnknownError } + + SaveSettingsResp (Err err) -> + UpdateResult { model | formResult = FormHttpError err } Cmd.none Sub.none AppNothing + + ReceiveServerSettings (Ok ( coll, user )) -> let - inSettings = - Maybe.withDefault settings model.settings + collDefaults = + Data.UiSettings.defaults - ( m_, sett ) = - Comp.UiSettingsForm.update inSettings lm model.formModel + userDefaults = + Data.UiSettings.merge coll collDefaults + + ( ( um, uc ), ( cm, cc ) ) = + case model.formData of + Just data -> + ( Comp.UiSettingsForm.initData flags user userDefaults data.userModel + , Comp.UiSettingsForm.initData flags coll collDefaults data.collModel + ) + + Nothing -> + ( Comp.UiSettingsForm.init flags user userDefaults + , Comp.UiSettingsForm.init flags coll collDefaults + ) + + model_ = + { model + | formData = + Just + { userSettings = user + , userModel = um + , collSettings = coll + , collModel = cm + } + , formModel = + case model.formModel of + ViewLoading -> + ViewUser + + _ -> + model.formModel + } + + cmds = + Cmd.batch + [ Cmd.map (UiFormMsg Data.AccountScope.User) uc + , Cmd.map (UiFormMsg Data.AccountScope.Collective) cc + ] in - { model = - { model - | formModel = m_ - , settings = - if sett == Nothing then - model.settings + UpdateResult model_ cmds Sub.none AppNothing - else - sett - , formResult = - if sett /= Nothing then - FormInit + ReceiveServerSettings (Err err) -> + unit { model | formResult = FormHttpError err } - else - model.formResult - } - , cmd = Cmd.none - , sub = Sub.none - , newSettings = Nothing - } - - UiSettingsMigrateMsg lm -> - let - result = - Comp.UiSettingsMigrate.update flags lm model.settingsMigrate - in - { model = { model | settingsMigrate = result.model } - , cmd = Cmd.map UiSettingsMigrateMsg result.cmd - , sub = Sub.map UiSettingsMigrateMsg result.sub - , newSettings = result.newSettings - } - - ReceiveBrowserSettings sett -> + ToggleExpandCollapse -> let lm = - UiSettingsMigrateMsg (Comp.UiSettingsMigrate.receiveBrowserSettings sett) + UiFormMsg (getViewScope model) Comp.UiSettingsForm.toggleAllTabs in update flags settings lm model - Submit -> - case model.settings of - Just s -> - { model = { model | formResult = FormInit } - , cmd = Api.saveClientSettings flags s (SaveSettingsResp s) - , sub = Sub.none - , newSettings = Nothing - } - - Nothing -> - { model = { model | formResult = FormUnchanged } - , cmd = Cmd.none - , sub = Sub.none - , newSettings = Nothing - } - - SaveSettingsResp newSettings (Ok res) -> - if res.success then - { model = { model | formResult = FormSaved } - , cmd = Cmd.none - , sub = Sub.none - , newSettings = Just newSettings - } - - else - { model = { model | formResult = FormUnknownError } - , cmd = Cmd.none - , sub = Sub.none - , newSettings = Nothing - } - - SaveSettingsResp _ (Err err) -> - UpdateResult { model | formResult = FormHttpError err } Cmd.none Sub.none Nothing - - UpdateSettings -> + SwitchForm scope -> let - ( fm, fc ) = - Comp.UiSettingsForm.init flags settings + forUser = + unit { model | formModel = ViewUser } + + forColl = + unit { model | formModel = ViewCollective } in - { model = { model | formModel = fm } - , cmd = Cmd.map UiSettingsFormMsg fc - , sub = Sub.none - , newSettings = Nothing - } + Data.AccountScope.fold forUser forColl scope + ResetFormState -> + case model.formResult of + FormSaved -> + unit { model | formResult = FormInit } - ---- View2 + _ -> + unit model isError : Model -> Bool @@ -211,7 +303,11 @@ isSuccess model = view2 : Texts -> Flags -> UiSettings -> String -> Model -> Html Msg -view2 texts flags settings classes model = +view2 texts flags _ classes model = + let + scope = + getViewScope model + in div [ class classes ] [ MB.view { start = @@ -221,14 +317,29 @@ view2 texts flags settings classes model = , title = texts.saveSettings , icon = Just "fa fa-save" } + , MB.SecondaryButton + { tagger = ToggleExpandCollapse + , label = "" + , title = texts.expandCollapse + , icon = Just "fa fa-compress" + } + ] + , end = + [ MB.RadioButton + { tagger = \_ -> SwitchForm Data.AccountScope.User + , label = texts.accountScope Data.AccountScope.User + , value = Data.AccountScope.fold True False scope + , id = "ui-settings-chooser-user" + } + , MB.RadioButton + { tagger = \_ -> SwitchForm Data.AccountScope.Collective + , label = texts.accountScope Data.AccountScope.Collective + , value = Data.AccountScope.fold False True scope + , id = "ui-settings-chooser-collective" + } ] - , end = [] , rootClasses = "mb-4" } - , div [] - [ Html.map UiSettingsMigrateMsg - (Comp.UiSettingsMigrate.view model.settingsMigrate) - ] , div [ classList [ ( S.successMessage, isSuccess model ) @@ -252,11 +363,55 @@ view2 texts flags settings classes model = FormUnknownError -> text texts.unknownSaveError ] - , Html.map UiSettingsFormMsg - (Comp.UiSettingsForm.view2 - texts.uiSettingsForm - flags - settings - model.formModel - ) + , case model.formModel of + ViewLoading -> + div [ class "h-24 md:relative" ] + [ Comp.Basic.loadingDimmer + { label = "" + , active = True + } + ] + + ViewCollective -> + case model.formData of + Just data -> + div [] + [ h2 [ class S.header2 ] + [ text texts.collectiveHeader + ] + , div [ class "py-1 opacity-80" ] + [ text texts.collectiveInfo + ] + , Html.map (UiFormMsg scope) + (Comp.UiSettingsForm.view2 + texts.uiSettingsForm + flags + data.collSettings + data.collModel + ) + ] + + Nothing -> + span [ class "hidden" ] [] + + ViewUser -> + case model.formData of + Just data -> + div [] + [ h2 [ class S.header2 ] + [ text texts.userHeader + ] + , div [ class "py-1 opacity-80" ] + [ text texts.userInfo + ] + , Html.map (UiFormMsg scope) + (Comp.UiSettingsForm.view2 texts.uiSettingsForm + flags + data.userSettings + data.userModel + ) + ] + + Nothing -> + span [ class "hidden" ] [] ] diff --git a/modules/webapp/src/main/elm/Comp/UiSettingsMigrate.elm b/modules/webapp/src/main/elm/Comp/UiSettingsMigrate.elm index a5b39ad3..d1aeed8e 100644 --- a/modules/webapp/src/main/elm/Comp/UiSettingsMigrate.elm +++ b/modules/webapp/src/main/elm/Comp/UiSettingsMigrate.elm @@ -17,6 +17,7 @@ module Comp.UiSettingsMigrate exposing import Api import Api.Model.BasicResult exposing (BasicResult) +import Data.AccountScope import Data.Flags exposing (Flags) import Data.UiSettings exposing (StoredUiSettings, UiSettings) import Html exposing (..) @@ -132,7 +133,10 @@ update flags msg model = Data.UiSettings.merge settings Data.UiSettings.defaults cmd = - Api.saveClientSettings flags uiSettings (SaveSettingsResp uiSettings) + Api.saveClientSettings flags + (Data.UiSettings.convert uiSettings) + Data.AccountScope.Collective + (SaveSettingsResp uiSettings) in { empty | model = MigrateRequestRunning, cmd = cmd } diff --git a/modules/webapp/src/main/elm/Data/AccountScope.elm b/modules/webapp/src/main/elm/Data/AccountScope.elm index 1fe287ec..07772f38 100644 --- a/modules/webapp/src/main/elm/Data/AccountScope.elm +++ b/modules/webapp/src/main/elm/Data/AccountScope.elm @@ -23,6 +23,11 @@ fold user coll scope = coll +all : List AccountScope +all = + [ Collective, User ] + + isUser : AccountScope -> Bool isUser scope = fold True False scope diff --git a/modules/webapp/src/main/elm/Data/AppEvent.elm b/modules/webapp/src/main/elm/Data/AppEvent.elm new file mode 100644 index 00000000..c15e912f --- /dev/null +++ b/modules/webapp/src/main/elm/Data/AppEvent.elm @@ -0,0 +1,13 @@ +{- + Copyright 2020 Eike K. & Contributors + + SPDX-License-Identifier: AGPL-3.0-or-later +-} + + +module Data.AppEvent exposing (AppEvent(..)) + + +type AppEvent + = AppNothing + | AppReloadUiSettings diff --git a/modules/webapp/src/main/elm/Data/UiSettings.elm b/modules/webapp/src/main/elm/Data/UiSettings.elm index 30a6c129..4e8c8194 100644 --- a/modules/webapp/src/main/elm/Data/UiSettings.elm +++ b/modules/webapp/src/main/elm/Data/UiSettings.elm @@ -7,7 +7,6 @@ module Data.UiSettings exposing ( ItemPattern - , Pos(..) , StoredUiSettings , UiSettings , cardPreviewSize @@ -15,22 +14,21 @@ module Data.UiSettings exposing , catColor , catColorFg2 , catColorString2 + , convert , defaults , documentationSite + , emptyStoredSettings , fieldHidden , fieldVisible , getUiLanguage , merge , mergeDefaults , pdfUrl - , posFromString - , posToString , storedUiSettingsDecoder , storedUiSettingsEncode , tagColor , tagColorFg2 , tagColorString2 - , toStoredUiSettings ) import Api.Model.Tag exposing (Tag) @@ -62,31 +60,53 @@ force default settings. -} type alias StoredUiSettings = { itemSearchPageSize : Maybe Int - , tagCategoryColors : List ( String, String ) + , tagCategoryColors : Maybe (List ( String, String )) , pdfMode : Maybe String , itemSearchNoteLength : Maybe Int - , itemDetailNotesPosition : Maybe String , searchMenuFolderCount : Maybe Int , searchMenuTagCount : Maybe Int , searchMenuTagCatCount : Maybe Int , formFields : Maybe (List String) - , itemDetailShortcuts : Bool - , searchMenuVisible : Bool - , editMenuVisible : Bool + , itemDetailShortcuts : Maybe Bool , cardPreviewSize : Maybe String , cardTitleTemplate : Maybe String , cardSubtitleTemplate : Maybe String - , searchStatsVisible : Bool - , cardPreviewFullWidth : Bool + , searchStatsVisible : Maybe Bool + , cardPreviewFullWidth : Maybe Bool , uiTheme : Maybe String - , sideMenuVisible : Bool - , powerSearchEnabled : Bool + , sideMenuVisible : Maybe Bool + , powerSearchEnabled : Maybe Bool , uiLang : Maybe String - , itemSearchShowGroups : Bool + , itemSearchShowGroups : Maybe Bool , itemSearchArrange : Maybe String } +emptyStoredSettings : StoredUiSettings +emptyStoredSettings = + { itemSearchPageSize = Nothing + , tagCategoryColors = Nothing + , pdfMode = Nothing + , itemSearchNoteLength = Nothing + , searchMenuFolderCount = Nothing + , searchMenuTagCount = Nothing + , searchMenuTagCatCount = Nothing + , formFields = Nothing + , itemDetailShortcuts = Nothing + , cardPreviewSize = Nothing + , cardTitleTemplate = Nothing + , cardSubtitleTemplate = Nothing + , searchStatsVisible = Nothing + , cardPreviewFullWidth = Nothing + , uiTheme = Nothing + , sideMenuVisible = Nothing + , powerSearchEnabled = Nothing + , uiLang = Nothing + , itemSearchShowGroups = Nothing + , itemSearchArrange = Nothing + } + + storedUiSettingsDecoder : Decode.Decoder StoredUiSettings storedUiSettingsDecoder = let @@ -96,66 +116,63 @@ storedUiSettingsDecoder = maybeString = Decode.maybe Decode.string - def = - defaults + maybeBool = + Decode.maybe Decode.bool in Decode.succeed StoredUiSettings |> P.optional "itemSearchPageSize" maybeInt Nothing - |> P.optional "tagCategoryColors" (Decode.keyValuePairs Decode.string) [] + |> P.optional "tagCategoryColors" (Decode.maybe <| Decode.keyValuePairs Decode.string) Nothing |> P.optional "pdfMode" maybeString Nothing |> P.optional "itemSearchNoteLength" maybeInt Nothing - |> P.optional "itemDetailNotesPosition" maybeString Nothing |> P.optional "searchMenuFolderCount" maybeInt Nothing |> P.optional "searchMenuTagCount" maybeInt Nothing |> P.optional "searchMenuTagCatCount" maybeInt Nothing |> P.optional "formFields" (Decode.maybe <| Decode.list Decode.string) Nothing - |> P.optional "itemDetailShortcuts" Decode.bool def.itemDetailShortcuts - |> P.optional "searchMenuVisible" Decode.bool def.searchMenuVisible - |> P.optional "editMenuVisible" Decode.bool def.editMenuVisible + |> P.optional "itemDetailShortcuts" maybeBool Nothing |> P.optional "cardPreviewSize" maybeString Nothing |> P.optional "cardTitleTemplate" maybeString Nothing |> P.optional "cardSubtitleTemplate" maybeString Nothing - |> P.optional "searchStatsVisible" Decode.bool def.searchStatsVisible - |> P.optional "cardPreviewFullWidth" Decode.bool def.cardPreviewFullWidth + |> P.optional "searchStatsVisible" maybeBool Nothing + |> P.optional "cardPreviewFullWidth" maybeBool Nothing |> P.optional "uiTheme" maybeString Nothing - |> P.optional "sideMenuVisible" Decode.bool def.sideMenuVisible - |> P.optional "powerSearchEnabled" Decode.bool def.powerSearchEnabled + |> P.optional "sideMenuVisible" maybeBool Nothing + |> P.optional "powerSearchEnabled" maybeBool Nothing |> P.optional "uiLang" maybeString Nothing - |> P.optional "itemSearchShowGroups" Decode.bool def.itemSearchShowGroups + |> P.optional "itemSearchShowGroups" maybeBool Nothing |> P.optional "itemSearchArrange" maybeString Nothing storedUiSettingsEncode : StoredUiSettings -> Encode.Value storedUiSettingsEncode value = let - maybeEnc enca ma = - Maybe.map enca ma |> Maybe.withDefault Encode.null + maybeEnc field enca ma = + Maybe.map (\a -> ( field, enca a )) ma in - Encode.object - [ ( "itemSearchPageSize", maybeEnc Encode.int value.itemSearchPageSize ) - , ( "tagCategoryColors", Encode.dict identity Encode.string (Dict.fromList value.tagCategoryColors) ) - , ( "pdfMode", maybeEnc Encode.string value.pdfMode ) - , ( "itemSearchNoteLength", maybeEnc Encode.int value.itemSearchNoteLength ) - , ( "itemDetailNotesPosition", maybeEnc Encode.string value.itemDetailNotesPosition ) - , ( "searchMenuFolderCount", maybeEnc Encode.int value.searchMenuFolderCount ) - , ( "searchMenuTagCount", maybeEnc Encode.int value.searchMenuTagCount ) - , ( "searchMenuTagCatCount", maybeEnc Encode.int value.searchMenuTagCatCount ) - , ( "formFields", maybeEnc (Encode.list Encode.string) value.formFields ) - , ( "itemDetailShortcuts", Encode.bool value.itemDetailShortcuts ) - , ( "searchMenuVisible", Encode.bool value.searchMenuVisible ) - , ( "editMenuVisible", Encode.bool value.editMenuVisible ) - , ( "cardPreviewSize", maybeEnc Encode.string value.cardPreviewSize ) - , ( "cardTitleTemplate", maybeEnc Encode.string value.cardTitleTemplate ) - , ( "cardSubtitleTemplate", maybeEnc Encode.string value.cardSubtitleTemplate ) - , ( "searchStatsVisible", Encode.bool value.searchStatsVisible ) - , ( "cardPreviewFullWidth", Encode.bool value.cardPreviewFullWidth ) - , ( "uiTheme", maybeEnc Encode.string value.uiTheme ) - , ( "sideMenuVisible", Encode.bool value.sideMenuVisible ) - , ( "powerSearchEnabled", Encode.bool value.powerSearchEnabled ) - , ( "uiLang", maybeEnc Encode.string value.uiLang ) - , ( "itemSearchShowGroups", Encode.bool value.itemSearchShowGroups ) - , ( "itemSearchArrange", maybeEnc Encode.string value.itemSearchArrange ) - ] + Encode.object <| + List.filterMap identity + [ maybeEnc "itemSearchPageSize" Encode.int value.itemSearchPageSize + , maybeEnc "tagCategoryColors" + (Encode.dict identity Encode.string) + (Maybe.map Dict.fromList value.tagCategoryColors) + , maybeEnc "pdfMode" Encode.string value.pdfMode + , maybeEnc "itemSearchNoteLength" Encode.int value.itemSearchNoteLength + , maybeEnc "searchMenuFolderCount" Encode.int value.searchMenuFolderCount + , maybeEnc "searchMenuTagCount" Encode.int value.searchMenuTagCount + , maybeEnc "searchMenuTagCatCount" Encode.int value.searchMenuTagCatCount + , maybeEnc "formFields" (Encode.list Encode.string) value.formFields + , maybeEnc "itemDetailShortcuts" Encode.bool value.itemDetailShortcuts + , maybeEnc "cardPreviewSize" Encode.string value.cardPreviewSize + , maybeEnc "cardTitleTemplate" Encode.string value.cardTitleTemplate + , maybeEnc "cardSubtitleTemplate" Encode.string value.cardSubtitleTemplate + , maybeEnc "searchStatsVisible" Encode.bool value.searchStatsVisible + , maybeEnc "cardPreviewFullWidth" Encode.bool value.cardPreviewFullWidth + , maybeEnc "uiTheme" Encode.string value.uiTheme + , maybeEnc "sideMenuVisible" Encode.bool value.sideMenuVisible + , maybeEnc "powerSearchEnabled" Encode.bool value.powerSearchEnabled + , maybeEnc "uiLang" Encode.string value.uiLang + , maybeEnc "itemSearchShowGroups" Encode.bool value.itemSearchShowGroups + , maybeEnc "itemSearchArrange" Encode.string value.itemSearchArrange + ] {-| Settings for the web ui. These fields are all mandatory, since @@ -171,14 +188,11 @@ type alias UiSettings = , tagCategoryColors : Dict String Color , pdfMode : PdfMode , itemSearchNoteLength : Int - , itemDetailNotesPosition : Pos , searchMenuFolderCount : Int , searchMenuTagCount : Int , searchMenuTagCatCount : Int , formFields : List Field , itemDetailShortcuts : Bool - , searchMenuVisible : Bool - , editMenuVisible : Bool , cardPreviewSize : BasicSize , cardTitleTemplate : ItemPattern , cardSubtitleTemplate : ItemPattern @@ -205,48 +219,17 @@ readPattern str = |> Maybe.map (ItemPattern str) -type Pos - = Top - | Bottom - - -posToString : Pos -> String -posToString pos = - case pos of - Top -> - "top" - - Bottom -> - "bottom" - - -posFromString : String -> Maybe Pos -posFromString str = - case str of - "top" -> - Just Top - - "bottom" -> - Just Bottom - - _ -> - Nothing - - defaults : UiSettings defaults = { itemSearchPageSize = 60 , tagCategoryColors = Dict.empty , pdfMode = Data.Pdf.Detect , itemSearchNoteLength = 0 - , itemDetailNotesPosition = Bottom , searchMenuFolderCount = 3 , searchMenuTagCount = 6 , searchMenuTagCatCount = 3 , formFields = Data.Fields.all , itemDetailShortcuts = False - , searchMenuVisible = False - , editMenuVisible = False , cardPreviewSize = Data.BasicSize.Medium , cardTitleTemplate = { template = Data.ItemTemplate.name @@ -273,7 +256,8 @@ merge given fallback = choose given.itemSearchPageSize fallback.itemSearchPageSize , tagCategoryColors = Dict.union - (Dict.fromList given.tagCategoryColors + (Maybe.map Dict.fromList given.tagCategoryColors + |> Maybe.withDefault Dict.empty |> Dict.map (\_ -> Data.Color.fromString) |> Dict.filter (\_ -> \mc -> mc /= Nothing) |> Dict.map (\_ -> Maybe.withDefault Data.Color.Grey) @@ -285,9 +269,6 @@ merge given fallback = |> Maybe.withDefault fallback.pdfMode , itemSearchNoteLength = choose given.itemSearchNoteLength fallback.itemSearchNoteLength - , itemDetailNotesPosition = - choose (Maybe.andThen posFromString given.itemDetailNotesPosition) - fallback.itemDetailNotesPosition , searchMenuFolderCount = choose given.searchMenuFolderCount fallback.searchMenuFolderCount @@ -299,9 +280,7 @@ merge given fallback = choose (Maybe.map Data.Fields.fromList given.formFields) fallback.formFields - , itemDetailShortcuts = given.itemDetailShortcuts - , searchMenuVisible = given.searchMenuVisible - , editMenuVisible = given.editMenuVisible + , itemDetailShortcuts = choose given.itemDetailShortcuts fallback.itemDetailShortcuts , cardPreviewSize = given.cardPreviewSize |> Maybe.andThen Data.BasicSize.fromString @@ -312,17 +291,17 @@ merge given fallback = , cardSubtitleTemplate = Maybe.andThen readPattern given.cardSubtitleTemplate |> Maybe.withDefault fallback.cardSubtitleTemplate - , searchStatsVisible = given.searchStatsVisible - , cardPreviewFullWidth = given.cardPreviewFullWidth + , searchStatsVisible = choose given.searchStatsVisible fallback.searchStatsVisible + , cardPreviewFullWidth = choose given.cardPreviewFullWidth fallback.cardPreviewFullWidth , uiTheme = Maybe.andThen Data.UiTheme.fromString given.uiTheme |> Maybe.withDefault fallback.uiTheme - , sideMenuVisible = given.sideMenuVisible - , powerSearchEnabled = given.powerSearchEnabled + , sideMenuVisible = choose given.sideMenuVisible fallback.sideMenuVisible + , powerSearchEnabled = choose given.powerSearchEnabled fallback.powerSearchEnabled , uiLang = Maybe.map Messages.fromIso2 given.uiLang - |> Maybe.withDefault Messages.UiLanguage.English - , itemSearchShowGroups = given.itemSearchShowGroups + |> Maybe.withDefault fallback.uiLang + , itemSearchShowGroups = choose given.itemSearchShowGroups fallback.itemSearchShowGroups , itemSearchArrange = Maybe.andThen Data.ItemArrange.fromString given.itemSearchArrange |> Maybe.withDefault fallback.itemSearchArrange @@ -334,37 +313,35 @@ mergeDefaults given = merge given defaults -toStoredUiSettings : UiSettings -> StoredUiSettings -toStoredUiSettings settings = +convert : UiSettings -> StoredUiSettings +convert settings = { itemSearchPageSize = Just settings.itemSearchPageSize , tagCategoryColors = Dict.map (\_ -> Data.Color.toString) settings.tagCategoryColors |> Dict.toList + |> Just , pdfMode = Just (Data.Pdf.asString settings.pdfMode) , itemSearchNoteLength = Just settings.itemSearchNoteLength - , itemDetailNotesPosition = Just (posToString settings.itemDetailNotesPosition) , searchMenuFolderCount = Just settings.searchMenuFolderCount , searchMenuTagCount = Just settings.searchMenuTagCount , searchMenuTagCatCount = Just settings.searchMenuTagCatCount , formFields = List.map Data.Fields.toString settings.formFields |> Just - , itemDetailShortcuts = settings.itemDetailShortcuts - , searchMenuVisible = settings.searchMenuVisible - , editMenuVisible = settings.editMenuVisible + , itemDetailShortcuts = Just settings.itemDetailShortcuts , cardPreviewSize = settings.cardPreviewSize |> Data.BasicSize.asString |> Just , cardTitleTemplate = settings.cardTitleTemplate.pattern |> Just , cardSubtitleTemplate = settings.cardSubtitleTemplate.pattern |> Just - , searchStatsVisible = settings.searchStatsVisible - , cardPreviewFullWidth = settings.cardPreviewFullWidth + , searchStatsVisible = Just settings.searchStatsVisible + , cardPreviewFullWidth = Just settings.cardPreviewFullWidth , uiTheme = Just (Data.UiTheme.toString settings.uiTheme) - , sideMenuVisible = settings.sideMenuVisible - , powerSearchEnabled = settings.powerSearchEnabled + , sideMenuVisible = Just settings.sideMenuVisible + , powerSearchEnabled = Just settings.powerSearchEnabled , uiLang = Just <| Messages.toIso2 settings.uiLang - , itemSearchShowGroups = settings.itemSearchShowGroups + , itemSearchShowGroups = Just settings.itemSearchShowGroups , itemSearchArrange = Data.ItemArrange.asString settings.itemSearchArrange |> Just } diff --git a/modules/webapp/src/main/elm/Main.elm b/modules/webapp/src/main/elm/Main.elm index 3569ad5c..d972f35b 100644 --- a/modules/webapp/src/main/elm/Main.elm +++ b/modules/webapp/src/main/elm/Main.elm @@ -14,7 +14,6 @@ import App.View2 import Browser exposing (Document) import Browser.Navigation exposing (Key) import Data.Flags exposing (Flags) -import Data.NotificationChannel import Data.UiSettings import Html exposing (..) import Html.Attributes exposing (..) @@ -93,6 +92,5 @@ subscriptions : Model -> Sub Msg subscriptions model = Sub.batch [ model.subs - , Ports.receiveUiSettings ReceiveBrowserSettings , Ports.receiveServerEvent ReceiveWsMessage ] diff --git a/modules/webapp/src/main/elm/Messages/Comp/UiSettingsForm.elm b/modules/webapp/src/main/elm/Messages/Comp/UiSettingsForm.elm index a09151a3..771bab51 100644 --- a/modules/webapp/src/main/elm/Messages/Comp/UiSettingsForm.elm +++ b/modules/webapp/src/main/elm/Messages/Comp/UiSettingsForm.elm @@ -56,6 +56,7 @@ type alias Texts = , fieldLabel : Field -> String , templateHelpMessage : String , pdfMode : PdfMode -> String + , resetLabel : String } @@ -131,6 +132,7 @@ and if that is not present the person. If both are absent a dash `-` is rendered. """ , pdfMode = Messages.Data.PdfMode.gb + , resetLabel = "Reset" } @@ -208,4 +210,5 @@ oder, wenn diese leer ist, die Person. Sind beide leer wird ein `-` dargestellt. """ , pdfMode = Messages.Data.PdfMode.de + , resetLabel = "Zurücksetzen" } diff --git a/modules/webapp/src/main/elm/Messages/Comp/UiSettingsManage.elm b/modules/webapp/src/main/elm/Messages/Comp/UiSettingsManage.elm index 77eb7037..dd7d56f2 100644 --- a/modules/webapp/src/main/elm/Messages/Comp/UiSettingsManage.elm +++ b/modules/webapp/src/main/elm/Messages/Comp/UiSettingsManage.elm @@ -15,16 +15,23 @@ import Http import Messages.Basics import Messages.Comp.HttpError import Messages.Comp.UiSettingsForm +import Messages.Data.AccountScope type alias Texts = { basics : Messages.Basics.Texts , uiSettingsForm : Messages.Comp.UiSettingsForm.Texts + , accountScope : Messages.Data.AccountScope.Texts , saveSettings : String , settingsUnchanged : String , settingsSaved : String , unknownSaveError : String , httpError : Http.Error -> String + , userHeader : String + , userInfo : String + , collectiveHeader : String + , collectiveInfo : String + , expandCollapse : String } @@ -32,11 +39,17 @@ gb : Texts gb = { basics = Messages.Basics.gb , uiSettingsForm = Messages.Comp.UiSettingsForm.gb + , accountScope = Messages.Data.AccountScope.gb , saveSettings = "Save settings" , settingsUnchanged = "Settings unchanged or invalid." , settingsSaved = "Settings saved." , unknownSaveError = "Unknown error while trying to save settings." , httpError = Messages.Comp.HttpError.gb + , userHeader = "Personal settings" + , userInfo = "Your personal settings override those of the collective. On reset, settings are taken from the collective settings." + , collectiveHeader = "Collective settings" + , collectiveInfo = "These settings apply to all users, unless overriden by personal ones. A reset loads the provided default values of the application." + , expandCollapse = "Expand/collapse all" } @@ -44,9 +57,15 @@ de : Texts de = { basics = Messages.Basics.de , uiSettingsForm = Messages.Comp.UiSettingsForm.de + , accountScope = Messages.Data.AccountScope.de , saveSettings = "Einstellungen speichern" , settingsUnchanged = "Einstellungen nicht verändert oder ungültig." , settingsSaved = "Einstellungen gespeichert" , unknownSaveError = "Unbekannter Fehler beim Speichern der Einstellungen." , httpError = Messages.Comp.HttpError.de + , userHeader = "Persönliche Einstellungen" + , userInfo = "Die persönlichen Einstellungen überschreiben die des Kollektivs. Wenn Einstellungen zurückgesetzt werden, gelten automatisch die Werte des Kollektivs." + , collectiveHeader = "Kollektiv Einstellungen" + , collectiveInfo = "Diese Einstellungen sind für alle Benutzer, können aber in den persönlichen Einstellungen überschrieben werden. Durch ein Zurücksetzen erhält man die bereitgestellten Standardwerte der Anwendung." + , expandCollapse = "Alle ein-/ausklappen" } diff --git a/modules/webapp/src/main/elm/Messages/Page/UserSettings.elm b/modules/webapp/src/main/elm/Messages/Page/UserSettings.elm index 99879774..e030fdda 100644 --- a/modules/webapp/src/main/elm/Messages/Page/UserSettings.elm +++ b/modules/webapp/src/main/elm/Messages/Page/UserSettings.elm @@ -80,8 +80,7 @@ gb = , changePassword = "Change Password" , channelSettings = "Notification Channels" , uiSettingsInfo = - "These settings only affect the web ui. They are stored in the browser, " - ++ "so they are separated between browsers and devices." + "These settings only affect the web ui. Settings can be stored to the collective or to your personal user. Personal settings are prefered when both values exist." , scanMailboxInfo1 = "Docspell can scan folders of your mailbox to import your mails. " ++ "You need to provide a connection in " @@ -144,7 +143,7 @@ de = , channelSettings = "Benachrichtigungskanäle" , changePassword = "Passwort ändern" , uiSettingsInfo = - "Diese Einstellungen sind für die Web-Oberfläche." + "Diese Einstellungen sind für die Web-Oberfläche. Es kann entweder für das ganze Kollektiv Einstellungen gemacht werden oder persönliche. Die persönlichen Einstellungen werden bevorzugt, falls beide gesetzt sind." , scanMailboxInfo1 = """Docspell kann Postfächer durchsuchen und E-Mails importieren. Dafür sind E-Mail-Einstellungen (IMAP) notwendig.""" diff --git a/modules/webapp/src/main/elm/Page/Search/Data.elm b/modules/webapp/src/main/elm/Page/Search/Data.elm index 06d6bc05..694eff8f 100644 --- a/modules/webapp/src/main/elm/Page/Search/Data.elm +++ b/modules/webapp/src/main/elm/Page/Search/Data.elm @@ -109,8 +109,7 @@ initSelectViewModel flags = type ViewMode - = SimpleView - | SearchView + = SearchView | SelectView SelectViewModel | PublishView Comp.PublishItems.Model @@ -149,9 +148,6 @@ init flags viewMode = menuCollapsed : Model -> Bool menuCollapsed model = case model.viewMode of - SimpleView -> - True - SearchView -> False @@ -165,9 +161,6 @@ menuCollapsed model = selectActive : Model -> Bool selectActive model = case model.viewMode of - SimpleView -> - False - SearchView -> False @@ -181,9 +174,6 @@ selectActive model = editActive : Model -> Bool editActive model = case model.viewMode of - SimpleView -> - False - SearchView -> False @@ -203,7 +193,6 @@ type Msg | ItemSearchResp Bool (Result Http.Error ItemLightList) | ItemSearchAddResp (Result Http.Error ItemLightList) | DoSearch SearchType - | ToggleSearchMenu | ToggleSelectView | LoadMore | SetBasicSearch String @@ -231,7 +220,7 @@ type Msg | KeyUpPowerSearchbarMsg (Maybe KeyCode) | RequestReprocessSelected | ReprocessSelectedConfirmed - | ClientSettingsSaveResp UiSettings (Result Http.Error BasicResult) + | ClientSettingsSaveResp (Result Http.Error BasicResult) | RemoveItem String | MergeSelectedItems | MergeItemsMsg Comp.ItemMerge.Msg diff --git a/modules/webapp/src/main/elm/Page/Search/Update.elm b/modules/webapp/src/main/elm/Page/Search/Update.elm index 6db4874d..83dde95c 100644 --- a/modules/webapp/src/main/elm/Page/Search/Update.elm +++ b/modules/webapp/src/main/elm/Page/Search/Update.elm @@ -22,7 +22,9 @@ import Comp.LinkTarget exposing (LinkTarget) import Comp.PowerSearchInput import Comp.PublishItems import Comp.SearchMenu +import Data.AppEvent exposing (AppEvent(..)) import Data.Flags exposing (Flags) +import Data.ItemArrange import Data.ItemQuery as Q import Data.ItemSelection import Data.Items @@ -44,7 +46,7 @@ type alias UpdateResult = { model : Model , cmd : Cmd Msg , sub : Sub Msg - , newSettings : Maybe UiSettings + , appEvent : AppEvent } @@ -74,7 +76,7 @@ update bookmarkId mId key flags texts settings msg model = model DoNothing -> - UpdateResult model Cmd.none Sub.none Nothing + UpdateResult model Cmd.none Sub.none AppNothing ResetSearch -> let @@ -274,34 +276,10 @@ update bookmarkId mId key flags texts settings msg model = else doSearch param model - ToggleSearchMenu -> - let - nextView = - case model.viewMode of - SimpleView -> - SearchView - - SearchView -> - SimpleView - - SelectView _ -> - SimpleView - - PublishView q -> - PublishView q - in - withSub - ( { model | viewMode = nextView } - , Cmd.none - ) - ToggleSelectView -> let ( nextView, cmd ) = case model.viewMode of - SimpleView -> - ( SelectView <| initSelectViewModel flags, loadEditModel flags ) - SearchView -> ( SelectView <| initSelectViewModel flags, loadEditModel flags ) @@ -642,11 +620,7 @@ update bookmarkId mId key flags texts settings msg model = SelectView { svm | mergeModel = result.model } Comp.ItemMerge.OutcomeMerged -> - if settings.searchMenuVisible then - SearchView - - else - SimpleView + SearchView model_ = { model | viewMode = nextView } @@ -834,17 +808,10 @@ update bookmarkId mId key flags texts settings msg model = UiSettingsUpdated -> let defaultViewMode = - if settings.searchMenuVisible then - SearchView - - else - SimpleView + SearchView viewMode = case model.viewMode of - SimpleView -> - defaultViewMode - SearchView -> defaultViewMode @@ -868,26 +835,26 @@ update bookmarkId mId key flags texts settings msg model = TogglePreviewFullWidth -> let - newSettings = - { settings | cardPreviewFullWidth = not settings.cardPreviewFullWidth } + newSettings s = + { s | cardPreviewFullWidth = Just (not settings.cardPreviewFullWidth) } cmd = - Api.saveClientSettings flags newSettings (ClientSettingsSaveResp newSettings) + Api.saveUserClientSettingsBy flags newSettings ClientSettingsSaveResp in noSub ( { model | viewMenuOpen = False }, cmd ) - ClientSettingsSaveResp newSettings (Ok res) -> + ClientSettingsSaveResp (Ok res) -> if res.success then { model = model , cmd = Cmd.none , sub = Sub.none - , newSettings = Just newSettings + , appEvent = AppReloadUiSettings } else noSub ( model, Cmd.none ) - ClientSettingsSaveResp _ (Err _) -> + ClientSettingsSaveResp (Err _) -> noSub ( model, Cmd.none ) PowerSearchMsg lm -> @@ -1015,21 +982,21 @@ update bookmarkId mId key flags texts settings msg model = ToggleShowGroups -> let - newSettings = - { settings | itemSearchShowGroups = not settings.itemSearchShowGroups } + newSettings s = + { s | itemSearchShowGroups = Just (not settings.itemSearchShowGroups) } cmd = - Api.saveClientSettings flags newSettings (ClientSettingsSaveResp newSettings) + Api.saveUserClientSettingsBy flags newSettings ClientSettingsSaveResp in noSub ( { model | viewMenuOpen = False }, cmd ) ToggleArrange am -> let - newSettings = - { settings | itemSearchArrange = am } + newSettings s = + { s | itemSearchArrange = Data.ItemArrange.asString am |> Just } cmd = - Api.saveClientSettings flags newSettings (ClientSettingsSaveResp newSettings) + Api.saveUserClientSettingsBy flags newSettings ClientSettingsSaveResp in noSub ( { model | viewMenuOpen = False }, cmd ) @@ -1201,5 +1168,5 @@ makeResult ( m, c, s ) = { model = m , cmd = c , sub = s - , newSettings = Nothing + , appEvent = AppNothing } diff --git a/modules/webapp/src/main/elm/Page/Search/View2.elm b/modules/webapp/src/main/elm/Page/Search/View2.elm index 8977bae4..534c2707 100644 --- a/modules/webapp/src/main/elm/Page/Search/View2.elm +++ b/modules/webapp/src/main/elm/Page/Search/View2.elm @@ -93,9 +93,6 @@ mainView texts flags settings model = (publishResults texts settings flags model pm) ] - SimpleView -> - Nothing - SearchView -> Nothing in @@ -109,7 +106,7 @@ mainView texts flags settings model = bookmarkQueryWidget : Texts -> UiSettings -> Flags -> Model -> List (Html Msg) -bookmarkQueryWidget texts settings flags model = +bookmarkQueryWidget texts _ _ model = case model.topWidgetModel of BookmarkQuery m -> [ div [ class "px-2 mb-4 border-l border-r border-b dark:border-slate-600" ] @@ -136,7 +133,7 @@ itemMergeView texts settings svm = publishResults : Texts -> UiSettings -> Flags -> Model -> Comp.PublishItems.Model -> List (Html Msg) -publishResults texts settings flags model pm = +publishResults texts settings flags _ pm = [ Html.map PublishViewMsg (Comp.PublishItems.view texts.publishItems settings flags pm) ] @@ -188,9 +185,6 @@ confirmModal texts model = itemsBar : Texts -> Flags -> UiSettings -> Model -> List (Html Msg) itemsBar texts flags settings model = case model.viewMode of - SimpleView -> - [ defaultMenuBar texts flags settings model ] - SearchView -> [ defaultMenuBar texts flags settings model ] diff --git a/modules/webapp/src/main/elm/Page/Share/Data.elm b/modules/webapp/src/main/elm/Page/Share/Data.elm index 35cd76c5..aa96acd1 100644 --- a/modules/webapp/src/main/elm/Page/Share/Data.elm +++ b/modules/webapp/src/main/elm/Page/Share/Data.elm @@ -18,6 +18,7 @@ import Comp.SearchMenu import Comp.SharePasswordForm import Data.Flags exposing (Flags) import Data.ItemArrange exposing (ItemArrange) +import Data.UiSettings exposing (UiSettings) import Http import Page.Search.Data exposing (Msg(..)) import Set exposing (Set) @@ -53,6 +54,7 @@ type alias Model = , initialized : Bool , contentSearch : Maybe String , searchMode : SearchBarMode + , uiSettings : UiSettings , viewMode : { menuOpen : Bool , showGroups : Bool @@ -75,6 +77,7 @@ emptyModel flags = , initialized = False , contentSearch = Nothing , searchMode = SearchBarContent + , uiSettings = Data.UiSettings.defaults , viewMode = { menuOpen = False , showGroups = True @@ -107,6 +110,7 @@ type Msg = VerifyResp (Result Http.Error ShareVerifyResult) | SearchResp (Result Http.Error ItemLightList) | StatsResp Bool (Result Http.Error SearchStats) + | UiSettingsResp (Result Http.Error UiSettings) | PasswordMsg Comp.SharePasswordForm.Msg | SearchMenuMsg Comp.SearchMenu.Msg | PowerSearchMsg Comp.PowerSearchInput.Msg diff --git a/modules/webapp/src/main/elm/Page/Share/Sidebar.elm b/modules/webapp/src/main/elm/Page/Share/Sidebar.elm index 11c31457..8fbcef90 100644 --- a/modules/webapp/src/main/elm/Page/Share/Sidebar.elm +++ b/modules/webapp/src/main/elm/Page/Share/Sidebar.elm @@ -10,7 +10,6 @@ module Page.Share.Sidebar exposing (..) import Comp.SearchMenu import Comp.Tabs import Data.Flags exposing (Flags) -import Data.UiSettings exposing (UiSettings) import Html exposing (..) import Html.Attributes exposing (..) import Messages.Page.Share exposing (Texts) @@ -18,8 +17,8 @@ import Page.Share.Data exposing (Model, Msg(..)) import Util.ItemDragDrop -view : Texts -> Flags -> UiSettings -> Model -> Html Msg -view texts flags settings model = +view : Texts -> Flags -> Model -> Html Msg +view texts flags model = let hideTrashTab tab default = case tab of @@ -41,7 +40,7 @@ view texts flags settings model = ddDummy flags searchMenuCfg - settings + model.uiSettings model.searchMenuModel ) ] diff --git a/modules/webapp/src/main/elm/Page/Share/Update.elm b/modules/webapp/src/main/elm/Page/Share/Update.elm index 238c092b..a3482580 100644 --- a/modules/webapp/src/main/elm/Page/Share/Update.elm +++ b/modules/webapp/src/main/elm/Page/Share/Update.elm @@ -43,7 +43,10 @@ update flags settings shareId msg model = , verifyResult = res , searchInProgress = True } - , makeSearchCmd flags True model + , Cmd.batch + [ makeSearchCmd flags True model + , Api.clientSettingsShare flags res.token UiSettingsResp + ] ) else if res.passwordRequired then @@ -242,6 +245,12 @@ update flags settings shareId msg model = in noSub ( { model | viewMode = next }, Cmd.none ) + UiSettingsResp (Ok s) -> + noSub ( { model | uiSettings = s }, Cmd.none ) + + UiSettingsResp (Err _) -> + noSub ( model, Cmd.none ) + noSub : ( Model, Cmd Msg ) -> UpdateResult noSub ( m, c ) = diff --git a/modules/webapp/src/main/elm/Page/Share/View.elm b/modules/webapp/src/main/elm/Page/Share/View.elm index 69bbb9eb..084b8c39 100644 --- a/modules/webapp/src/main/elm/Page/Share/View.elm +++ b/modules/webapp/src/main/elm/Page/Share/View.elm @@ -11,11 +11,9 @@ import Api.Model.VersionInfo exposing (VersionInfo) import Comp.Basic as B import Comp.SharePasswordForm import Data.Flags exposing (Flags) -import Data.Items import Data.UiSettings exposing (UiSettings) import Html exposing (..) import Html.Attributes exposing (..) -import Html.Events exposing (onInput, onSubmit) import Messages.Page.Share exposing (Texts) import Page.Share.Data exposing (..) import Page.Share.Menubar as Menubar @@ -25,19 +23,19 @@ import Styles as S viewSidebar : Texts -> Bool -> Flags -> UiSettings -> Model -> Html Msg -viewSidebar texts visible flags settings model = +viewSidebar texts visible flags _ model = div [ id "sidebar" , class S.sidebar , class S.sidebarBg , classList [ ( "hidden", not visible || model.mode /= ModeShare ) ] ] - [ Sidebar.view texts flags settings model + [ Sidebar.view texts flags model ] viewContent : Texts -> Flags -> VersionInfo -> UiSettings -> String -> Model -> Html Msg -viewContent texts flags versionInfo uiSettings shareId model = +viewContent texts flags versionInfo _ shareId model = case model.mode of ModeInitial -> div @@ -60,15 +58,15 @@ viewContent texts flags versionInfo uiSettings shareId model = passwordContent texts flags versionInfo model ModeShare -> - mainContent texts flags uiSettings shareId model + mainContent texts flags shareId model --- Helpers -mainContent : Texts -> Flags -> UiSettings -> String -> Model -> Html Msg -mainContent texts flags settings shareId model = +mainContent : Texts -> Flags -> String -> Model -> Html Msg +mainContent texts flags shareId model = div [ id "content" , class "h-full flex flex-col" @@ -82,7 +80,7 @@ mainContent texts flags settings shareId model = ] , Menubar.view texts flags model , errorMessage texts model - , Results.view texts settings flags shareId model + , Results.view texts model.uiSettings flags shareId model ] diff --git a/modules/webapp/src/main/elm/Page/ShareDetail/Data.elm b/modules/webapp/src/main/elm/Page/ShareDetail/Data.elm index 2d6e1b3a..615931d8 100644 --- a/modules/webapp/src/main/elm/Page/ShareDetail/Data.elm +++ b/modules/webapp/src/main/elm/Page/ShareDetail/Data.elm @@ -14,6 +14,7 @@ import Api.Model.ShareVerifyResult exposing (ShareVerifyResult) import Comp.SharePasswordForm import Comp.UrlCopy import Data.Flags exposing (Flags) +import Data.UiSettings exposing (UiSettings) import Http @@ -37,12 +38,14 @@ type alias Model = , pageError : PageError , attachMenuOpen : Bool , visibleAttach : Int + , uiSettings : UiSettings } type Msg = VerifyResp (Result Http.Error ShareVerifyResult) | GetItemResp (Result Http.Error ItemDetail) + | UiSettingsResp (Result Http.Error UiSettings) | PasswordMsg Comp.SharePasswordForm.Msg | SelectActiveAttachment Int | ToggleSelectAttach @@ -58,6 +61,7 @@ emptyModel vm = , pageError = PageErrorNone , attachMenuOpen = False , visibleAttach = 0 + , uiSettings = Data.UiSettings.defaults } diff --git a/modules/webapp/src/main/elm/Page/ShareDetail/Update.elm b/modules/webapp/src/main/elm/Page/ShareDetail/Update.elm index efa880d3..ffcd81bf 100644 --- a/modules/webapp/src/main/elm/Page/ShareDetail/Update.elm +++ b/modules/webapp/src/main/elm/Page/ShareDetail/Update.elm @@ -25,7 +25,10 @@ update shareId itemId flags msg model = , viewMode = ViewLoading , verifyResult = res } - , Api.itemDetailShare flags res.token itemId GetItemResp + , Cmd.batch + [ Api.itemDetailShare flags res.token itemId GetItemResp + , Api.clientSettingsShare flags res.token UiSettingsResp + ] ) else if res.passwordRequired then @@ -93,3 +96,9 @@ update shareId itemId flags msg model = Comp.UrlCopy.update lm in ( model, cmd ) + + UiSettingsResp (Ok s) -> + ( { model | uiSettings = s }, Cmd.none ) + + UiSettingsResp (Err _) -> + ( model, Cmd.none ) diff --git a/modules/webapp/src/main/elm/Page/ShareDetail/View.elm b/modules/webapp/src/main/elm/Page/ShareDetail/View.elm index 210a0c12..8105598b 100644 --- a/modules/webapp/src/main/elm/Page/ShareDetail/View.elm +++ b/modules/webapp/src/main/elm/Page/ShareDetail/View.elm @@ -16,7 +16,7 @@ import Comp.UrlCopy import Data.Fields import Data.Flags exposing (Flags) import Data.Icons as Icons -import Data.ItemTemplate as IT exposing (ItemTemplate) +import Data.ItemTemplate as IT import Data.UiSettings exposing (UiSettings) import Html exposing (..) import Html.Attributes exposing (..) @@ -33,7 +33,7 @@ import Util.String viewSidebar : Texts -> Bool -> Flags -> UiSettings -> String -> String -> Model -> Html Msg -viewSidebar texts visible flags settings shareId itemId model = +viewSidebar texts visible flags _ shareId itemId model = div [ id "sidebar" , classList [ ( "hidden", not visible || model.viewMode /= ViewNormal ) ] @@ -103,6 +103,7 @@ itemData texts flags model shareId itemId = div [ class "flex ml-2 mt-1 font-semibold hover:opacity-75" , class S.basicLabel + , class (Data.UiSettings.tagColorString2 tag model.uiSettings) ] [ i [ class "fa fa-tag mr-2" ] [] , text tag.name diff --git a/modules/webapp/src/main/elm/Page/UserSettings/Data.elm b/modules/webapp/src/main/elm/Page/UserSettings/Data.elm index 2c71dda6..141e86e6 100644 --- a/modules/webapp/src/main/elm/Page/UserSettings/Data.elm +++ b/modules/webapp/src/main/elm/Page/UserSettings/Data.elm @@ -42,10 +42,10 @@ type alias Model = init : Flags -> UiSettings -> ( Model, Cmd Msg ) -init flags settings = +init flags _ = let ( um, uc ) = - Comp.UiSettingsManage.init flags settings + Comp.UiSettingsManage.init flags ( otpm, otpc ) = Comp.OtpSetup.init flags @@ -107,5 +107,3 @@ type Msg | NotificationHookMsg Comp.NotificationHookManage.Msg | PeriodicQueryMsg Comp.PeriodicQueryTaskManage.Msg | ChannelMsg Comp.NotificationChannelManage.Msg - | UpdateSettings - | ReceiveBrowserSettings StoredUiSettings diff --git a/modules/webapp/src/main/elm/Page/UserSettings/Update.elm b/modules/webapp/src/main/elm/Page/UserSettings/Update.elm index 656674ad..eec01a4e 100644 --- a/modules/webapp/src/main/elm/Page/UserSettings/Update.elm +++ b/modules/webapp/src/main/elm/Page/UserSettings/Update.elm @@ -17,6 +17,7 @@ import Comp.OtpSetup import Comp.PeriodicQueryTaskManage import Comp.ScanMailboxManage import Comp.UiSettingsManage +import Data.AppEvent exposing (AppEvent(..)) import Data.Flags exposing (Flags) import Data.UiSettings exposing (UiSettings) import Page.UserSettings.Data exposing (..) @@ -26,10 +27,15 @@ type alias UpdateResult = { model : Model , cmd : Cmd Msg , sub : Sub Msg - , newSettings : Maybe UiSettings + , appEvent : AppEvent } +unit : Model -> UpdateResult +unit model = + UpdateResult model Cmd.none Sub.none AppNothing + + update : Flags -> UiSettings -> Msg -> Model -> UpdateResult update flags settings msg model = case msg of @@ -47,7 +53,7 @@ update flags settings msg model = { model = { m | emailSettingsModel = em } , cmd = Cmd.map EmailSettingsMsg c , sub = Sub.none - , newSettings = Nothing + , appEvent = AppNothing } ImapSettingsTab -> @@ -58,18 +64,14 @@ update flags settings msg model = { model = { m | imapSettingsModel = em } , cmd = Cmd.map ImapSettingsMsg c , sub = Sub.none - , newSettings = Nothing + , appEvent = AppNothing } ChangePassTab -> - UpdateResult m Cmd.none Sub.none Nothing + unit m NotificationTab -> - { model = m - , cmd = Cmd.none - , sub = Sub.none - , newSettings = Nothing - } + unit m NotificationWebhookTab -> let @@ -79,7 +81,7 @@ update flags settings msg model = { model = m , cmd = Cmd.map NotificationHookMsg nc , sub = Sub.none - , newSettings = Nothing + , appEvent = AppNothing } NotificationQueriesTab -> @@ -88,7 +90,7 @@ update flags settings msg model = Cmd.map NotificationMsg (Tuple.second (Comp.DueItemsTaskManage.init flags)) in - UpdateResult m initCmd Sub.none Nothing + UpdateResult m initCmd Sub.none AppNothing NotificationDueItemsTab -> let @@ -96,7 +98,7 @@ update flags settings msg model = Cmd.map NotificationMsg (Tuple.second (Comp.DueItemsTaskManage.init flags)) in - UpdateResult m initCmd Sub.none Nothing + UpdateResult m initCmd Sub.none AppNothing ScanMailboxTab -> let @@ -104,16 +106,24 @@ update flags settings msg model = Cmd.map ScanMailboxMsg (Tuple.second (Comp.ScanMailboxManage.init flags)) in - UpdateResult m initCmd Sub.none Nothing + UpdateResult m initCmd Sub.none AppNothing UiSettingsTab -> - UpdateResult m Cmd.none Sub.none Nothing + let + ( um, uc ) = + Comp.UiSettingsManage.init flags + in + { model = { m | uiSettingsModel = um } + , cmd = Cmd.map UiSettingsMsg uc + , sub = Sub.none + , appEvent = AppNothing + } OtpTab -> - UpdateResult m Cmd.none Sub.none Nothing + unit m ChannelTab -> - UpdateResult m Cmd.none Sub.none Nothing + unit m ChangePassMsg m -> let @@ -123,7 +133,7 @@ update flags settings msg model = { model = { model | changePassModel = m2 } , cmd = Cmd.map ChangePassMsg c2 , sub = Sub.none - , newSettings = Nothing + , appEvent = AppNothing } EmailSettingsMsg m -> @@ -134,7 +144,7 @@ update flags settings msg model = { model = { model | emailSettingsModel = m2 } , cmd = Cmd.map EmailSettingsMsg c2 , sub = Sub.none - , newSettings = Nothing + , appEvent = AppNothing } ImapSettingsMsg m -> @@ -145,7 +155,7 @@ update flags settings msg model = { model = { model | imapSettingsModel = m2 } , cmd = Cmd.map ImapSettingsMsg c2 , sub = Sub.none - , newSettings = Nothing + , appEvent = AppNothing } NotificationMsg lm -> @@ -156,7 +166,7 @@ update flags settings msg model = { model = { model | notificationModel = m2 } , cmd = Cmd.map NotificationMsg c2 , sub = Sub.none - , newSettings = Nothing + , appEvent = AppNothing } ScanMailboxMsg lm -> @@ -167,7 +177,7 @@ update flags settings msg model = { model = { model | scanMailboxModel = m2 } , cmd = Cmd.map ScanMailboxMsg c2 , sub = Sub.none - , newSettings = Nothing + , appEvent = AppNothing } UiSettingsMsg lm -> @@ -178,7 +188,7 @@ update flags settings msg model = { model = { model | uiSettingsModel = res.model } , cmd = Cmd.map UiSettingsMsg res.cmd , sub = Sub.map UiSettingsMsg res.sub - , newSettings = res.newSettings + , appEvent = res.appEvent } OtpSetupMsg lm -> @@ -189,7 +199,7 @@ update flags settings msg model = { model = { model | otpSetupModel = otpm } , cmd = Cmd.map OtpSetupMsg otpc , sub = Sub.none - , newSettings = Nothing + , appEvent = AppNothing } NotificationHookMsg lm -> @@ -200,7 +210,7 @@ update flags settings msg model = { model = { model | notificationHookModel = hm } , cmd = Cmd.map NotificationHookMsg hc , sub = Sub.none - , newSettings = Nothing + , appEvent = AppNothing } ChannelMsg lm -> @@ -211,22 +221,9 @@ update flags settings msg model = { model = { model | channelModel = cm } , cmd = Cmd.map ChannelMsg cc , sub = Sub.none - , newSettings = Nothing + , appEvent = AppNothing } - UpdateSettings -> - update flags - settings - (UiSettingsMsg Comp.UiSettingsManage.UpdateSettings) - model - - ReceiveBrowserSettings sett -> - let - lm = - Comp.UiSettingsManage.ReceiveBrowserSettings sett - in - update flags settings (UiSettingsMsg lm) model - PeriodicQueryMsg lm -> let ( pqm, pqc, pqs ) = @@ -235,5 +232,5 @@ update flags settings msg model = { model = { model | periodicQueryModel = pqm } , cmd = Cmd.map PeriodicQueryMsg pqc , sub = Sub.map PeriodicQueryMsg pqs - , newSettings = Nothing + , appEvent = AppNothing } diff --git a/modules/webapp/src/main/elm/Ports.elm b/modules/webapp/src/main/elm/Ports.elm index 8a348b85..09ff2b44 100644 --- a/modules/webapp/src/main/elm/Ports.elm +++ b/modules/webapp/src/main/elm/Ports.elm @@ -11,9 +11,7 @@ port module Ports exposing , printElement , receiveCheckQueryResult , receiveServerEvent - , receiveUiSettings , removeAccount - , requestUiSettings , setAccount , setUiTheme ) @@ -21,7 +19,6 @@ port module Ports exposing import Api.Model.AuthResult exposing (AuthResult) import Data.QueryParseResult exposing (QueryParseResult) import Data.ServerEvent exposing (ServerEvent) -import Data.UiSettings exposing (StoredUiSettings) import Data.UiTheme exposing (UiTheme) import Json.Decode as D @@ -46,12 +43,6 @@ port receiveCheckQueryResult : (QueryParseResult -> msg) -> Sub msg port initClipboard : ( String, String ) -> Cmd msg -port receiveUiSettings : (StoredUiSettings -> msg) -> Sub msg - - -port requestUiSettings : AuthResult -> Cmd msg - - {-| Creates a new window/tab, writes the contents of the given element and calls the print dialog. -} diff --git a/modules/webapp/src/main/webjar/docspell.js b/modules/webapp/src/main/webjar/docspell.js index 4b32212e..0b81ff02 100644 --- a/modules/webapp/src/main/webjar/docspell.js +++ b/modules/webapp/src/main/webjar/docspell.js @@ -55,25 +55,6 @@ elmApp.ports.removeAccount.subscribe(function() { closeWS(); }); -elmApp.ports.requestUiSettings.subscribe(function(args) { - console.log("Requesting ui settings"); - var account = args; - var collective = account ? account.collective : null; - var user = account ? account.user : null; - if (collective && user) { - var key = collective + "/" + user + "/uiSettings"; - var settings = localStorage.getItem(key); - try { - var data = settings ? JSON.parse(settings) : null; - if (data) { - console.log("Sending browser ui settings"); - elmApp.ports.receiveUiSettings.send(data); - } - } catch (error) { - console.log(error); - } - } -}); var docspell_clipboards = {};