mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-07-04 16:48:26 +00:00
Client settings per collective and user
Client settings can be stored at the user and and the collective. The settings used in the application are merged from these two settings, where any user setting takes precedence. The form can now manage both variants. Refs: #838
This commit is contained in:
@ -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)
|
||||
]
|
||||
)
|
||||
[]
|
||||
|
@ -9,6 +9,7 @@ module Comp.UiSettingsForm exposing
|
||||
( Model
|
||||
, Msg
|
||||
, init
|
||||
, toggleAllTabs
|
||||
, update
|
||||
, view2
|
||||
)
|
||||
@ -30,7 +31,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, Pos(..), StoredUiSettings, UiSettings)
|
||||
import Dict exposing (Dict)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
@ -73,6 +74,7 @@ type alias Model =
|
||||
, uiLangModel : Comp.FixedDropdown.Model UiLanguage
|
||||
, uiLang : UiLanguage
|
||||
, openTabs : Set String
|
||||
, defaults : UiSettings
|
||||
}
|
||||
|
||||
|
||||
@ -111,61 +113,69 @@ 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 )
|
||||
|
||||
|
||||
type Msg
|
||||
@ -188,14 +198,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 +260,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 +276,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 +292,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 +308,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 +324,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 +339,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 +378,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 +398,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 +409,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 +433,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 +450,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 +467,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 +501,7 @@ update sett msg model =
|
||||
not model.sideMenuVisible
|
||||
in
|
||||
( { model | sideMenuVisible = next }
|
||||
, Just { sett | sideMenuVisible = next }
|
||||
, Just { sett | sideMenuVisible = Just next }
|
||||
)
|
||||
|
||||
TogglePowerSearch ->
|
||||
@ -438,7 +510,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 +526,7 @@ update sett msg model =
|
||||
Nothing
|
||||
|
||||
else
|
||||
Just { sett | uiLang = newLang }
|
||||
Just { sett | uiLang = Just (Messages.toIso2 newLang) }
|
||||
)
|
||||
|
||||
PdfModeMsg lm ->
|
||||
@ -470,9 +542,53 @@ 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 }
|
||||
|
||||
-- no reset here
|
||||
FieldsTab ->
|
||||
{ sett | formFields = Nothing }
|
||||
|
||||
nm =
|
||||
initModel flags newSettings model.defaults
|
||||
in
|
||||
( { nm | openTabs = model.openTabs }, Just newSettings )
|
||||
|
||||
|
||||
|
||||
--- View2
|
||||
@ -495,7 +611,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 +633,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 +649,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 "Reset"
|
||||
]
|
||||
in
|
||||
[ { name = "general"
|
||||
[ { name = akkordionTabName GeneralTab
|
||||
, title = texts.general
|
||||
, titleRight = []
|
||||
, titleRight = [ resetLink GeneralTab ]
|
||||
, info = Nothing
|
||||
, body =
|
||||
[ div [ class "mb-4 " ]
|
||||
@ -560,9 +687,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 +721,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 +793,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 +827,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 +853,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 +866,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" ]
|
||||
|
@ -16,26 +16,42 @@ 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 Styles as S
|
||||
|
||||
|
||||
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 +61,39 @@ 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
|
||||
|
||||
|
||||
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 +102,165 @@ 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_
|
||||
}
|
||||
, formResult =
|
||||
if sett /= Nothing then
|
||||
FormInit
|
||||
|
||||
else
|
||||
model.formResult
|
||||
}
|
||||
|
||||
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_
|
||||
}
|
||||
, formResult =
|
||||
if sett /= Nothing then
|
||||
FormInit
|
||||
|
||||
else
|
||||
model.formResult
|
||||
}
|
||||
|
||||
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
|
||||
in
|
||||
{ result | appEvent = AppReloadUiSettings }
|
||||
|
||||
_ ->
|
||||
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 ) =
|
||||
Comp.UiSettingsForm.init flags user userDefaults
|
||||
|
||||
( cm, cc ) =
|
||||
Comp.UiSettingsForm.init flags coll collDefaults
|
||||
|
||||
model_ =
|
||||
{ model
|
||||
| formData =
|
||||
Just
|
||||
{ userSettings = user
|
||||
, userModel = um
|
||||
, collSettings = coll
|
||||
, collModel = cm
|
||||
}
|
||||
, formModel = ViewUser
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
||||
--- View2
|
||||
Data.AccountScope.fold forUser forColl scope
|
||||
|
||||
|
||||
isError : Model -> Bool
|
||||
@ -211,7 +288,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 +302,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 +348,52 @@ 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
|
||||
]
|
||||
, 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" ] []
|
||||
]
|
||||
|
@ -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 }
|
||||
|
||||
|
Reference in New Issue
Block a user