diff --git a/modules/restapi/src/main/resources/docspell-openapi.yml b/modules/restapi/src/main/resources/docspell-openapi.yml index 3b2ba5cd..36529d29 100644 --- a/modules/restapi/src/main/resources/docspell-openapi.yml +++ b/modules/restapi/src/main/resources/docspell-openapi.yml @@ -4756,7 +4756,7 @@ components: $ref: "#/components/schemas/IdName" concPerson: $ref: "#/components/schemas/IdName" - concEquip: + concEquipment: $ref: "#/components/schemas/IdName" folder: $ref: "#/components/schemas/IdName" diff --git a/modules/webapp/src/main/elm/App/Update.elm b/modules/webapp/src/main/elm/App/Update.elm index 5d40b1c0..47f0ecdb 100644 --- a/modules/webapp/src/main/elm/App/Update.elm +++ b/modules/webapp/src/main/elm/App/Update.elm @@ -7,6 +7,7 @@ import Api import App.Data exposing (..) import Browser exposing (UrlRequest(..)) import Browser.Navigation as Nav +import Comp.LinkTarget import Data.Flags import Page exposing (Page(..)) import Page.CollectiveSettings.Data @@ -193,7 +194,7 @@ updateItemDetail lmsg model = inav = Page.Home.Data.itemNav model.itemDetailModel.detail.item.id model.homeModel - ( lm, lc, ls ) = + result = Page.ItemDetail.Update.update model.key model.flags @@ -201,12 +202,18 @@ updateItemDetail lmsg model = model.uiSettings lmsg model.itemDetailModel + + model_ = + { model + | itemDetailModel = result.model + } + + ( hm, hc, hs ) = + updateHome (Page.Home.Data.SetLinkTarget result.linkTarget) model_ in - ( { model - | itemDetailModel = lm - } - , Cmd.map ItemDetailMsg lc - , Sub.map ItemDetailMsg ls + ( hm + , Cmd.batch [ Cmd.map ItemDetailMsg result.cmd, hc ] + , Sub.batch [ Sub.map ItemDetailMsg result.sub, hs ] ) diff --git a/modules/webapp/src/main/elm/Comp/FolderSelect.elm b/modules/webapp/src/main/elm/Comp/FolderSelect.elm index 35d4a3da..4e516756 100644 --- a/modules/webapp/src/main/elm/Comp/FolderSelect.elm +++ b/modules/webapp/src/main/elm/Comp/FolderSelect.elm @@ -1,7 +1,9 @@ module Comp.FolderSelect exposing ( Model , Msg + , deselect , init + , setSelected , update , updateDrop , view @@ -32,6 +34,23 @@ init selected all = } +setSelected : String -> Model -> Maybe Msg +setSelected id model = + List.filter (\fi -> fi.id == id) model.all + |> List.head + |> Maybe.map Toggle + + +deselect : Model -> Maybe Msg +deselect model = + case model.selected of + Just id -> + setSelected id model + + Nothing -> + Nothing + + --- Update diff --git a/modules/webapp/src/main/elm/Comp/ItemCard.elm b/modules/webapp/src/main/elm/Comp/ItemCard.elm index b449bcb7..6b3a1938 100644 --- a/modules/webapp/src/main/elm/Comp/ItemCard.elm +++ b/modules/webapp/src/main/elm/Comp/ItemCard.elm @@ -1,10 +1,19 @@ -module Comp.ItemCard exposing (..) +module Comp.ItemCard exposing + ( Model + , Msg + , UpdateResult + , ViewConfig + , init + , update + , view + ) import Api import Api.Model.AttachmentLight exposing (AttachmentLight) import Api.Model.HighlightEntry exposing (HighlightEntry) +import Api.Model.IdName exposing (IdName) import Api.Model.ItemLight exposing (ItemLight) -import Data.BasicSize +import Comp.LinkTarget exposing (LinkTarget(..)) import Data.Direction import Data.Fields import Data.Icons as Icons @@ -16,7 +25,6 @@ import Html.Events exposing (onClick) import Markdown import Page exposing (Page(..)) import Set exposing (Set) -import Util.Html import Util.ItemDragDrop as DD import Util.List import Util.Maybe @@ -33,6 +41,7 @@ type Msg = CyclePreview ItemLight | ToggleSelectItem (Set String) String | ItemDDMsg DD.Msg + | SetLinkTarget LinkTarget type alias ViewConfig = @@ -45,6 +54,7 @@ type alias UpdateResult = { model : Model , dragModel : DD.Model , selection : ItemSelection + , linkTarget : LinkTarget } @@ -89,7 +99,7 @@ update ddm msg model = ddd = DD.update lm ddm in - UpdateResult model ddd.model Data.ItemSelection.Inactive + UpdateResult model ddd.model Data.ItemSelection.Inactive LinkNone ToggleSelectItem ids id -> let @@ -100,7 +110,7 @@ update ddm msg model = else Set.insert id ids in - UpdateResult model ddm (Data.ItemSelection.Active newSet) + UpdateResult model ddm (Data.ItemSelection.Active newSet) LinkNone CyclePreview item -> let @@ -113,6 +123,10 @@ update ddm msg model = UpdateResult { model | previewAttach = next } ddm Data.ItemSelection.Inactive + LinkNone + + SetLinkTarget target -> + UpdateResult model ddm Data.ItemSelection.Inactive target view : ViewConfig -> UiSettings -> Model -> ItemLight -> Html Msg @@ -204,31 +218,15 @@ metaDataContent settings item = fieldHidden f = Data.UiSettings.fieldHidden settings f - corr = - List.filterMap identity [ item.corrOrg, item.corrPerson ] - |> List.map .name - |> List.intersperse ", " - |> String.concat - - conc = - List.filterMap identity [ item.concPerson, item.concEquip ] - |> List.map .name - |> List.intersperse ", " - |> String.concat - - folder = - Maybe.map .name item.folder - |> Maybe.withDefault "" - dueDate = Maybe.map Util.Time.formatDateShort item.dueDate |> Maybe.withDefault "" in div [ class "content" ] - [ div [ class "ui horizontal list" ] + [ div [ class "ui horizontal link list" ] [ div [ classList - [ ( "item", True ) + [ ( "link item", True ) , ( "invisible hidden" , fieldHidden Data.Fields.CorrOrg && fieldHidden Data.Fields.CorrPerson @@ -236,10 +234,9 @@ metaDataContent settings item = ] , title "Correspondent" ] - [ Icons.correspondentIcon "" - , text " " - , Util.String.withDefault "-" corr |> text - ] + (Icons.correspondentIcon "" + :: Comp.LinkTarget.makeCorrLink item SetLinkTarget + ) , div [ classList [ ( "item", True ) @@ -250,10 +247,9 @@ metaDataContent settings item = ] , title "Concerning" ] - [ Icons.concernedIcon - , text " " - , Util.String.withDefault "-" conc |> text - ] + (Icons.concernedIcon + :: Comp.LinkTarget.makeConcLink item SetLinkTarget + ) , div [ classList [ ( "item", True ) @@ -262,8 +258,7 @@ metaDataContent settings item = , title "Folder" ] [ Icons.folderIcon "" - , text " " - , Util.String.withDefault "-" folder |> text + , Comp.LinkTarget.makeFolderLink item SetLinkTarget ] ] , div [ class "right floated meta" ] @@ -318,7 +313,7 @@ notesContent settings item = mainContent : Attribute Msg -> String -> Bool -> UiSettings -> ViewConfig -> ItemLight -> Html Msg -mainContent cardAction cardColor isConfirmed settings cfg item = +mainContent cardAction cardColor isConfirmed settings _ item = let dirIcon = i [ class (Data.Direction.iconFromMaybe item.direction) ] [] @@ -429,6 +424,7 @@ previewMenu model item mainAttach = [ class "ui compact basic icon button" , href attachUrl , target "_self" + , title "Open attachment file" ] [ i [ class "eye icon" ] [] ] diff --git a/modules/webapp/src/main/elm/Comp/ItemCardList.elm b/modules/webapp/src/main/elm/Comp/ItemCardList.elm index 24b942bb..50df7c86 100644 --- a/modules/webapp/src/main/elm/Comp/ItemCardList.elm +++ b/modules/webapp/src/main/elm/Comp/ItemCardList.elm @@ -14,6 +14,7 @@ import Api.Model.ItemLight exposing (ItemLight) import Api.Model.ItemLightGroup exposing (ItemLightGroup) import Api.Model.ItemLightList exposing (ItemLightList) import Comp.ItemCard +import Comp.LinkTarget exposing (LinkTarget) import Data.Flags exposing (Flags) import Data.ItemSelection exposing (ItemSelection) import Data.Items @@ -75,6 +76,7 @@ type alias UpdateResult = , cmd : Cmd Msg , dragModel : DD.Model , selection : ItemSelection + , linkTarget : LinkTarget } @@ -91,18 +93,30 @@ updateDrag dm _ msg model = newModel = { model | results = list } in - UpdateResult newModel Cmd.none dm Data.ItemSelection.Inactive + UpdateResult newModel + Cmd.none + dm + Data.ItemSelection.Inactive + Comp.LinkTarget.LinkNone AddResults list -> if list.groups == [] then - UpdateResult model Cmd.none dm Data.ItemSelection.Inactive + UpdateResult model + Cmd.none + dm + Data.ItemSelection.Inactive + Comp.LinkTarget.LinkNone else let newModel = { model | results = Data.Items.concat model.results list } in - UpdateResult newModel Cmd.none dm Data.ItemSelection.Inactive + UpdateResult newModel + Cmd.none + dm + Data.ItemSelection.Inactive + Comp.LinkTarget.LinkNone ItemCardMsg item lm -> let @@ -120,6 +134,7 @@ updateDrag dm _ msg model = Cmd.none result.dragModel result.selection + result.linkTarget @@ -134,7 +149,12 @@ type alias ViewConfig = view : ViewConfig -> UiSettings -> Model -> Html Msg view cfg settings model = - div [ class "ui container" ] + div + [ classList + [ ( "ui container", True ) + , ( "multi-select-mode", isMultiSelectMode cfg ) + ] + ] (List.map (viewGroup model cfg settings) model.results.groups) @@ -171,3 +191,17 @@ viewItem model cfg settings item = Comp.ItemCard.view vvcfg settings cardModel item in Html.map (ItemCardMsg item) cardHtml + + + +--- Helpers + + +isMultiSelectMode : ViewConfig -> Bool +isMultiSelectMode cfg = + case cfg.selection of + Data.ItemSelection.Active _ -> + True + + Data.ItemSelection.Inactive -> + False diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail.elm b/modules/webapp/src/main/elm/Comp/ItemDetail.elm index b16d4056..d2d09227 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail.elm @@ -6,7 +6,7 @@ module Comp.ItemDetail exposing ) import Browser.Navigation as Nav -import Comp.ItemDetail.Model exposing (Msg(..)) +import Comp.ItemDetail.Model exposing (Msg(..), UpdateResult) import Comp.ItemDetail.Update import Comp.ItemDetail.View exposing (..) import Data.Flags exposing (Flags) @@ -25,7 +25,7 @@ emptyModel = Comp.ItemDetail.Model.emptyModel -update : Nav.Key -> Flags -> ItemNav -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg ) +update : Nav.Key -> Flags -> ItemNav -> UiSettings -> Msg -> Model -> UpdateResult update = Comp.ItemDetail.Update.update diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/Model.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/Model.elm index 36aea44c..57625afc 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail/Model.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail/Model.elm @@ -4,8 +4,12 @@ module Comp.ItemDetail.Model exposing , Msg(..) , NotesField(..) , SaveNameState(..) + , UpdateResult , emptyModel , isEditNotes + , resultModel + , resultModelCmd + , resultModelCmdSub ) import Api.Model.BasicResult exposing (BasicResult) @@ -26,6 +30,7 @@ import Comp.Dropdown import Comp.Dropzone import Comp.ItemMail import Comp.KeyInput +import Comp.LinkTarget exposing (LinkTarget) import Comp.MarkdownInput import Comp.SentMails import Comp.YesNoDimmer @@ -273,9 +278,33 @@ type Msg | KeyInputMsg Comp.KeyInput.Msg | ToggleAttachMenu | UiSettingsUpdated + | SetLinkTarget LinkTarget type SaveNameState = Saving | SaveSuccess | SaveFailed + + +type alias UpdateResult = + { model : Model + , cmd : Cmd Msg + , sub : Sub Msg + , linkTarget : LinkTarget + } + + +resultModel : Model -> UpdateResult +resultModel model = + UpdateResult model Cmd.none Sub.none Comp.LinkTarget.LinkNone + + +resultModelCmd : ( Model, Cmd Msg ) -> UpdateResult +resultModelCmd ( model, cmd ) = + UpdateResult model cmd Sub.none Comp.LinkTarget.LinkNone + + +resultModelCmdSub : ( Model, Cmd Msg, Sub Msg ) -> UpdateResult +resultModelCmdSub ( model, cmd, sub ) = + UpdateResult model cmd sub Comp.LinkTarget.LinkNone diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm index 578a11ef..19ad419d 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm @@ -25,10 +25,15 @@ import Comp.ItemDetail.Model , Msg(..) , NotesField(..) , SaveNameState(..) + , UpdateResult , isEditNotes + , resultModel + , resultModelCmd + , resultModelCmdSub ) import Comp.ItemMail import Comp.KeyInput +import Comp.LinkTarget import Comp.MarkdownInput import Comp.OrgForm import Comp.PersonForm @@ -46,7 +51,6 @@ import Html.Attributes exposing (..) import Html5.DragDrop as DD import Http import Page exposing (Page(..)) -import Ports import Set exposing (Set) import Throttle import Time @@ -58,7 +62,7 @@ import Util.Maybe import Util.String -update : Nav.Key -> Flags -> ItemNav -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg ) +update : Nav.Key -> Flags -> ItemNav -> UiSettings -> Msg -> Model -> UpdateResult update key flags inav settings msg model = case msg of Init -> @@ -69,7 +73,7 @@ update key flags inav settings msg model = ( im, ic ) = Comp.ItemMail.init flags in - noSub + resultModelCmd ( { model | itemDatePicker = dp, dueDatePicker = dp, itemMail = im, visibleAttach = 0 } , Cmd.batch [ getOptions flags @@ -82,7 +86,7 @@ update key flags inav settings msg model = SetItem item -> let - ( m1, c1, s1 ) = + res1 = update key flags inav @@ -90,7 +94,7 @@ update key flags inav settings msg model = (TagDropdownMsg (Comp.Dropdown.SetSelection item.tags)) model - ( m2, c2, s2 ) = + res2 = update key flags inav @@ -103,9 +107,9 @@ update key flags inav settings msg model = ) ) ) - m1 + res1.model - ( m3, c3, s3 ) = + res3 = update key flags inav @@ -118,9 +122,9 @@ update key flags inav settings msg model = ) ) ) - m2 + res2.model - ( m4, c4, s4 ) = + res4 = update key flags inav @@ -133,9 +137,9 @@ update key flags inav settings msg model = ) ) ) - m3 + res3.model - ( m5, c5, s5 ) = + res5 = update key flags inav @@ -148,9 +152,9 @@ update key flags inav settings msg model = ) ) ) - m4 + res4.model - ( m6, c6, s6 ) = + res6 = update key flags inav @@ -163,12 +167,12 @@ update key flags inav settings msg model = ) ) ) - m5 + res5.model - ( m7, c7, s7 ) = - update key flags inav settings AddFilesReset m6 + res7 = + update key flags inav settings AddFilesReset res6.model - ( m8, c8, s8 ) = + res8 = update key flags inav @@ -181,7 +185,7 @@ update key flags inav settings msg model = ) ) ) - m7 + res7.model proposalCmd = if item.state == "created" then @@ -189,58 +193,73 @@ update key flags inav settings msg model = else Cmd.none - in - ( { m8 - | item = item - , nameModel = item.name - , nameState = SaveSuccess - , notesModel = item.notes - , notesField = - if Util.String.isNothingOrBlank item.notes then - EditNotes Comp.MarkdownInput.init - else - ViewNotes - , itemDate = item.itemDate - , dueDate = item.dueDate - , visibleAttach = 0 - , modalEdit = Nothing - } - , Cmd.batch - [ c1 - , c2 - , c3 - , c4 - , c5 - , c6 - , c7 - , c8 - , getOptions flags - , proposalCmd - , Api.getSentMails flags item.id SentMailsResp - ] - , Sub.batch [ s1, s2, s3, s4, s5, s6, s7, s8 ] - ) + lastModel = + res8.model + in + { model = + { lastModel + | item = item + , nameModel = item.name + , nameState = SaveSuccess + , notesModel = item.notes + , notesField = + if Util.String.isNothingOrBlank item.notes then + EditNotes Comp.MarkdownInput.init + + else + ViewNotes + , itemDate = item.itemDate + , dueDate = item.dueDate + , visibleAttach = 0 + , modalEdit = Nothing + } + , cmd = + Cmd.batch + [ res1.cmd + , res2.cmd + , res3.cmd + , res4.cmd + , res5.cmd + , res6.cmd + , res7.cmd + , res8.cmd + , getOptions flags + , proposalCmd + , Api.getSentMails flags item.id SentMailsResp + ] + , sub = + Sub.batch + [ res1.sub + , res2.sub + , res3.sub + , res4.sub + , res5.sub + , res6.sub + , res7.sub + , res8.sub + ] + , linkTarget = Comp.LinkTarget.LinkNone + } SetActiveAttachment pos -> - noSub - ( { model + resultModel + { model | visibleAttach = pos , sentMailsOpen = False , attachRename = Nothing - } - , Cmd.none - ) + } ToggleMenu -> - noSub ( { model | menuOpen = not model.menuOpen }, Cmd.none ) + resultModel + { model | menuOpen = not model.menuOpen } ReloadItem -> if model.item.id == "" then - noSub ( model, Cmd.none ) + resultModel model else - noSub ( model, Api.itemDetail flags model.item.id GetItemResp ) + resultModelCmd ( model, Api.itemDetail flags model.item.id GetItemResp ) FolderDropdownMsg m -> let @@ -260,7 +279,7 @@ update key flags inav settings msg model = else Cmd.none in - noSub ( newModel, Cmd.batch [ save, Cmd.map FolderDropdownMsg c2 ] ) + resultModelCmd ( newModel, Cmd.batch [ save, Cmd.map FolderDropdownMsg c2 ] ) TagDropdownMsg m -> let @@ -277,7 +296,7 @@ update key flags inav settings msg model = else Cmd.none in - noSub ( newModel, Cmd.batch [ save, Cmd.map TagDropdownMsg c2 ] ) + resultModelCmd ( newModel, Cmd.batch [ save, Cmd.map TagDropdownMsg c2 ] ) DirDropdownMsg m -> let @@ -294,7 +313,7 @@ update key flags inav settings msg model = else Cmd.none in - noSub ( newModel, Cmd.batch [ save, Cmd.map DirDropdownMsg c2 ] ) + resultModelCmd ( newModel, Cmd.batch [ save, Cmd.map DirDropdownMsg c2 ] ) OrgDropdownMsg m -> let @@ -314,7 +333,7 @@ update key flags inav settings msg model = else Cmd.none in - noSub ( newModel, Cmd.batch [ save, Cmd.map OrgDropdownMsg c2 ] ) + resultModelCmd ( newModel, Cmd.batch [ save, Cmd.map OrgDropdownMsg c2 ] ) CorrPersonMsg m -> let @@ -334,7 +353,7 @@ update key flags inav settings msg model = else Cmd.none in - noSub ( newModel, Cmd.batch [ save, Cmd.map CorrPersonMsg c2 ] ) + resultModelCmd ( newModel, Cmd.batch [ save, Cmd.map CorrPersonMsg c2 ] ) ConcPersonMsg m -> let @@ -354,7 +373,7 @@ update key flags inav settings msg model = else Cmd.none in - noSub ( newModel, Cmd.batch [ save, Cmd.map ConcPersonMsg c2 ] ) + resultModelCmd ( newModel, Cmd.batch [ save, Cmd.map ConcPersonMsg c2 ] ) ConcEquipMsg m -> let @@ -374,7 +393,7 @@ update key flags inav settings msg model = else Cmd.none in - noSub ( newModel, Cmd.batch [ save, Cmd.map ConcEquipMsg c2 ] ) + resultModelCmd ( newModel, Cmd.batch [ save, Cmd.map ConcEquipMsg c2 ] ) SetName str -> case Util.Maybe.fromString str of @@ -398,26 +417,22 @@ update key flags inav settings msg model = ) Nothing -> - noSub ( { model | nameModel = str, nameState = SaveFailed }, Cmd.none ) + resultModel { model | nameModel = str, nameState = SaveFailed } SetNotes str -> - noSub - ( { model | notesModel = Util.Maybe.fromString str } - , Cmd.none - ) + resultModel + { model | notesModel = Util.Maybe.fromString str } ToggleEditNotes -> - noSub - ( { model + resultModel + { model | notesField = if isEditNotes model.notesField then ViewNotes else EditNotes Comp.MarkdownInput.init - } - , Cmd.none - ) + } NotesEditMsg lm -> case model.notesField of @@ -426,26 +441,24 @@ update key flags inav settings msg model = ( lm2, str ) = Comp.MarkdownInput.update (Maybe.withDefault "" model.notesModel) lm em in - noSub - ( { model | notesField = EditNotes lm2, notesModel = Util.Maybe.fromString str } - , Cmd.none - ) + resultModel + { model | notesField = EditNotes lm2, notesModel = Util.Maybe.fromString str } ViewNotes -> - noSub ( model, Cmd.none ) + resultModel model SaveNotes -> - noSub ( model, setNotes flags model ) + resultModelCmd ( model, setNotes flags model ) ConfirmItem -> let resetCmds = resetHiddenFields settings flags model.item.id ResetHiddenMsg in - noSub ( model, Cmd.batch (Api.setConfirmed flags model.item.id SaveResp :: resetCmds) ) + resultModelCmd ( model, Cmd.batch (Api.setConfirmed flags model.item.id SaveResp :: resetCmds) ) UnconfirmItem -> - noSub ( model, Api.setUnconfirmed flags model.item.id SaveResp ) + resultModelCmd ( model, Api.setUnconfirmed flags model.item.id SaveResp ) ItemDatePickerMsg m -> let @@ -458,13 +471,13 @@ update key flags inav settings msg model = newModel = { model | itemDatePicker = dp, itemDate = Just (Comp.DatePicker.midOfDay date) } in - noSub ( newModel, setDate flags newModel newModel.itemDate ) + resultModelCmd ( newModel, setDate flags newModel newModel.itemDate ) _ -> - noSub ( { model | itemDatePicker = dp }, Cmd.none ) + resultModel { model | itemDatePicker = dp } RemoveDate -> - noSub ( { model | itemDate = Nothing }, setDate flags model Nothing ) + resultModelCmd ( { model | itemDate = Nothing }, setDate flags model Nothing ) DueDatePickerMsg m -> let @@ -477,13 +490,13 @@ update key flags inav settings msg model = newModel = { model | dueDatePicker = dp, dueDate = Just (Comp.DatePicker.midOfDay date) } in - noSub ( newModel, setDueDate flags newModel newModel.dueDate ) + resultModelCmd ( newModel, setDueDate flags newModel newModel.dueDate ) _ -> - noSub ( { model | dueDatePicker = dp }, Cmd.none ) + resultModel { model | dueDatePicker = dp } RemoveDueDate -> - noSub ( { model | dueDate = Nothing }, setDueDate flags model Nothing ) + resultModelCmd ( { model | dueDate = Nothing }, setDueDate flags model Nothing ) DeleteItemConfirm m -> let @@ -497,28 +510,28 @@ update key flags inav settings msg model = else Cmd.none in - noSub ( { model | deleteItemConfirm = cm }, cmd ) + resultModelCmd ( { model | deleteItemConfirm = cm }, cmd ) RequestDelete -> update key flags inav settings (DeleteItemConfirm Comp.YesNoDimmer.activate) model SetCorrOrgSuggestion idname -> - noSub ( model, setCorrOrg flags model (Just idname) ) + resultModelCmd ( model, setCorrOrg flags model (Just idname) ) SetCorrPersonSuggestion idname -> - noSub ( model, setCorrPerson flags model (Just idname) ) + resultModelCmd ( model, setCorrPerson flags model (Just idname) ) SetConcPersonSuggestion idname -> - noSub ( model, setConcPerson flags model (Just idname) ) + resultModelCmd ( model, setConcPerson flags model (Just idname) ) SetConcEquipSuggestion idname -> - noSub ( model, setConcEquip flags model (Just idname) ) + resultModelCmd ( model, setConcEquip flags model (Just idname) ) SetItemDateSuggestion date -> - noSub ( model, setDate flags model (Just date) ) + resultModelCmd ( model, setDate flags model (Just date) ) SetDueDateSuggestion date -> - noSub ( model, setDueDate flags model (Just date) ) + resultModelCmd ( model, setDueDate flags model (Just date) ) GetFolderResp (Ok fs) -> let @@ -542,20 +555,17 @@ update key flags inav settings msg model = update key flags inav settings (FolderDropdownMsg opts) model_ GetFolderResp (Err _) -> - noSub ( model, Cmd.none ) + resultModel model GetTagsResp (Ok tags) -> let tagList = Comp.Dropdown.SetOptions tags.items - - ( m1, c1, s1 ) = - update key flags inav settings (TagDropdownMsg tagList) model in - ( m1, c1, s1 ) + update key flags inav settings (TagDropdownMsg tagList) model GetTagsResp (Err _) -> - noSub ( model, Cmd.none ) + resultModel model GetOrgResp (Ok orgs) -> let @@ -565,23 +575,27 @@ update key flags inav settings msg model = update key flags inav settings (OrgDropdownMsg opts) model GetOrgResp (Err _) -> - noSub ( model, Cmd.none ) + resultModel model GetPersonResp (Ok ps) -> let opts = Comp.Dropdown.SetOptions ps.items - ( m1, c1, s1 ) = + res1 = update key flags inav settings (CorrPersonMsg opts) model - ( m2, c2, s2 ) = - update key flags inav settings (ConcPersonMsg opts) m1 + res2 = + update key flags inav settings (ConcPersonMsg opts) res1.model in - ( m2, Cmd.batch [ c1, c2 ], Sub.batch [ s1, s2 ] ) + { model = res2.model + , cmd = Cmd.batch [ res1.cmd, res2.cmd ] + , sub = Sub.batch [ res1.sub, res2.sub ] + , linkTarget = Comp.LinkTarget.LinkNone + } GetPersonResp (Err _) -> - noSub ( model, Cmd.none ) + resultModel model GetEquipResp (Ok equips) -> let @@ -594,63 +608,59 @@ update key flags inav settings msg model = update key flags inav settings (ConcEquipMsg opts) model GetEquipResp (Err _) -> - noSub ( model, Cmd.none ) + resultModel model SaveResp (Ok res) -> if res.success then - noSub ( model, Api.itemDetail flags model.item.id GetItemResp ) + resultModelCmd ( model, Api.itemDetail flags model.item.id GetItemResp ) else - noSub ( model, Cmd.none ) + resultModel model SaveResp (Err _) -> - noSub ( model, Cmd.none ) + resultModel model SaveNameResp (Ok res) -> if res.success then - noSub - ( { model + resultModel + { model | nameState = SaveSuccess , item = setItemName model.item model.nameModel - } - , Cmd.none - ) + } else - noSub - ( { model | nameState = SaveFailed } - , Cmd.none - ) + resultModel + { model | nameState = SaveFailed } SaveNameResp (Err _) -> - noSub ( { model | nameState = SaveFailed }, Cmd.none ) + resultModel { model | nameState = SaveFailed } DeleteResp (Ok res) -> if res.success then case inav.next of Just id -> - noSub ( model, Page.set key (ItemDetailPage id) ) + resultModelCmd ( model, Page.set key (ItemDetailPage id) ) Nothing -> - noSub ( model, Page.set key HomePage ) + resultModelCmd ( model, Page.set key HomePage ) else - noSub ( model, Cmd.none ) + resultModel model DeleteResp (Err _) -> - noSub ( model, Cmd.none ) + resultModel model GetItemResp (Ok item) -> update key flags inav settings (SetItem item) model GetItemResp (Err _) -> - noSub ( model, Cmd.none ) + resultModel model GetProposalResp (Ok ip) -> - noSub ( { model | itemProposals = ip }, Cmd.none ) + resultModel { model | itemProposals = ip } GetProposalResp (Err _) -> - noSub ( model, Cmd.none ) + resultModel model ItemMailMsg m -> let @@ -659,10 +669,10 @@ update key flags inav settings msg model = in case fa of Comp.ItemMail.FormNone -> - noSub ( { model | itemMail = im }, Cmd.map ItemMailMsg ic ) + resultModelCmd ( { model | itemMail = im }, Cmd.map ItemMailMsg ic ) Comp.ItemMail.FormCancel -> - noSub + resultModelCmd ( { model | itemMail = Comp.ItemMail.clear im , mailOpen = False @@ -679,7 +689,7 @@ update key flags inav settings msg model = , conn = sm.conn } in - noSub + resultModelCmd ( { model | mailSending = True } , Cmd.batch [ Cmd.map ItemMailMsg ic @@ -706,14 +716,12 @@ update key flags inav settings msg model = else Nothing in - noSub - ( { model + resultModel + { model | mailOpen = newOpen , addFilesOpen = filesOpen , mailSendResult = sendResult - } - , Cmd.none - ) + } SendMailResp (Ok br) -> let @@ -724,7 +732,7 @@ update key flags inav settings msg model = else model.itemMail in - noSub + resultModelCmd ( { model | itemMail = mm , mailSending = False @@ -742,41 +750,37 @@ update key flags inav settings msg model = errmsg = Util.Http.errorToString err in - noSub - ( { model + resultModel + { model | mailSendResult = Just (BasicResult False errmsg) , mailSending = False - } - , Cmd.none - ) + } SentMailsMsg m -> let sm = Comp.SentMails.update m model.sentMails in - noSub ( { model | sentMails = sm }, Cmd.none ) + resultModel { model | sentMails = sm } ToggleSentMails -> - noSub ( { model | sentMailsOpen = not model.sentMailsOpen }, Cmd.none ) + resultModel { model | sentMailsOpen = not model.sentMailsOpen } SentMailsResp (Ok list) -> let sm = Comp.SentMails.initMails list.items in - noSub ( { model | sentMails = sm }, Cmd.none ) + resultModel { model | sentMails = sm } SentMailsResp (Err _) -> - noSub ( model, Cmd.none ) + resultModel model AttachMetaClick id -> case Dict.get id model.attachMeta of Just _ -> - noSub - ( { model | attachMetaOpen = not model.attachMetaOpen } - , Cmd.none - ) + resultModel + { model | attachMetaOpen = not model.attachMetaOpen } Nothing -> let @@ -786,7 +790,7 @@ update key flags inav settings msg model = nextMeta = Dict.insert id am model.attachMeta in - noSub + resultModelCmd ( { model | attachMeta = nextMeta, attachMetaOpen = True } , Cmd.map (AttachMetaMsg id) ac ) @@ -798,17 +802,15 @@ update key flags inav settings msg model = am = Comp.AttachmentMeta.update lmsg cm in - noSub - ( { model | attachMeta = Dict.insert id am model.attachMeta } - , Cmd.none - ) + resultModel + { model | attachMeta = Dict.insert id am model.attachMeta } Nothing -> - noSub ( model, Cmd.none ) + resultModel model TogglePdfNativeView default -> - noSub - ( { model + resultModel + { model | pdfNativeView = case model.pdfNativeView of Just flag -> @@ -816,9 +818,7 @@ update key flags inav settings msg model = Nothing -> Just (not default) - } - , Cmd.none - ) + } DeleteAttachConfirm attachId lmsg -> let @@ -832,17 +832,17 @@ update key flags inav settings msg model = else Cmd.none in - noSub ( { model | deleteAttachConfirm = cm }, cmd ) + resultModelCmd ( { model | deleteAttachConfirm = cm }, cmd ) DeleteAttachResp (Ok res) -> if res.success then update key flags inav settings ReloadItem model else - noSub ( model, Cmd.none ) + resultModel model DeleteAttachResp (Err _) -> - noSub ( model, Cmd.none ) + resultModel model RequestDeleteAttachment id -> update key @@ -853,8 +853,8 @@ update key flags inav settings msg model = model AddFilesToggle -> - noSub - ( { model + resultModel + { model | addFilesOpen = not model.addFilesOpen , mailOpen = if model.addFilesOpen == False then @@ -862,9 +862,7 @@ update key flags inav settings msg model = else model.mailOpen - } - , Cmd.none - ) + } AddFilesMsg lm -> let @@ -874,22 +872,20 @@ update key flags inav settings msg model = nextFiles = model.selectedFiles ++ df in - noSub + resultModelCmd ( { model | addFilesModel = dm, selectedFiles = nextFiles } , Cmd.map AddFilesMsg dc ) AddFilesReset -> - noSub - ( { model + resultModel + { model | selectedFiles = [] , addFilesModel = Comp.Dropzone.init Comp.Dropzone.defaultSettings , completed = Set.empty , errored = Set.empty , loading = Dict.empty - } - , Cmd.none - ) + } AddFilesSubmitUpload -> let @@ -909,10 +905,11 @@ update key flags inav settings msg model = List.map (\fid -> ( fid, 0 )) fileids |> Dict.fromList in - ( { model | loading = newLoading, addFilesModel = cm2 } - , uploads - , tracker - ) + resultModelCmdSub + ( { model | loading = newLoading, addFilesModel = cm2 } + , uploads + , tracker + ) AddFilesUploadResp fileid (Ok res) -> let @@ -940,10 +937,7 @@ update key flags inav settings msg model = , loading = load } in - noSub - ( newModel - , Cmd.none - ) + resultModel newModel AddFilesUploadResp fileid (Err _) -> let @@ -953,7 +947,7 @@ update key flags inav settings msg model = load = Dict.remove fileid model.loading in - noSub ( { model | errored = errs, loading = load }, Cmd.none ) + resultModel { model | errored = errs, loading = load } AddFilesProgress fileid progress -> let @@ -970,10 +964,8 @@ update key flags inav settings msg model = newLoading = Dict.insert fileid percent model.loading in - noSub - ( { model | loading = newLoading } - , Cmd.none - ) + resultModel + { model | loading = newLoading } AttachDDMsg lm -> let @@ -995,7 +987,7 @@ update key flags inav settings msg model = Nothing -> Cmd.none in - noSub ( { model | attachDD = model_ }, cmd ) + resultModelCmd ( { model | attachDD = model_ }, cmd ) ModalEditMsg lm -> case model.modalEdit of @@ -1015,31 +1007,27 @@ update key flags inav settings msg model = Nothing -> ( { model | modalEdit = Just mm_ }, Cmd.none ) in - noSub ( model_, Cmd.batch [ cmd_, Cmd.map ModalEditMsg mc_ ] ) + resultModelCmd ( model_, Cmd.batch [ cmd_, Cmd.map ModalEditMsg mc_ ] ) Nothing -> - noSub ( model, Cmd.none ) + resultModel model StartTagModal -> - noSub - ( { model + resultModel + { model | modalEdit = Just (Comp.DetailEdit.initTagByName model.item.id "") - } - , Cmd.none - ) + } StartCorrOrgModal -> - noSub - ( { model + resultModel + { model | modalEdit = Just (Comp.DetailEdit.initOrg model.item.id Comp.OrgForm.emptyModel ) - } - , Cmd.none - ) + } StartEditCorrOrgModal -> let @@ -1054,10 +1042,10 @@ update key flags inav settings msg model = ( m, c ) = Comp.DetailEdit.editOrg flags oid Comp.OrgForm.emptyModel in - noSub ( { model | modalEdit = Just m }, Cmd.map ModalEditMsg c ) + resultModelCmd ( { model | modalEdit = Just m }, Cmd.map ModalEditMsg c ) Nothing -> - ( model, Cmd.none, Sub.none ) + resultModel model StartEditEquipModal -> let @@ -1072,36 +1060,32 @@ update key flags inav settings msg model = ( m, c ) = Comp.DetailEdit.editEquip flags eid Comp.EquipmentForm.emptyModel in - noSub ( { model | modalEdit = Just m }, Cmd.map ModalEditMsg c ) + resultModelCmd ( { model | modalEdit = Just m }, Cmd.map ModalEditMsg c ) Nothing -> - ( model, Cmd.none, Sub.none ) + resultModel model StartCorrPersonModal -> - noSub - ( { model + resultModel + { model | modalEdit = Just (Comp.DetailEdit.initCorrPerson model.item.id Comp.PersonForm.emptyModel ) - } - , Cmd.none - ) + } StartConcPersonModal -> - noSub - ( { model + resultModel + { model | modalEdit = Just (Comp.DetailEdit.initConcPerson model.item.id Comp.PersonForm.emptyModel ) - } - , Cmd.none - ) + } StartEditPersonModal pm -> let @@ -1116,26 +1100,24 @@ update key flags inav settings msg model = ( m, c ) = Comp.DetailEdit.editPerson flags pid Comp.PersonForm.emptyModel in - noSub ( { model | modalEdit = Just m }, Cmd.map ModalEditMsg c ) + resultModelCmd ( { model | modalEdit = Just m }, Cmd.map ModalEditMsg c ) Nothing -> - ( model, Cmd.none, Sub.none ) + resultModel model StartEquipModal -> - noSub - ( { model + resultModel + { model | modalEdit = Just (Comp.DetailEdit.initEquip model.item.id Comp.EquipmentForm.emptyModel ) - } - , Cmd.none - ) + } CloseModal -> - noSub ( { model | modalEdit = Nothing }, Cmd.none ) + resultModel { model | modalEdit = Nothing } EditAttachNameStart id -> case model.attachRename of @@ -1147,27 +1129,25 @@ update key flags inav settings msg model = in case name of Just n -> - noSub ( { model | attachRename = Just (AttachmentRename id n) }, Cmd.none ) + resultModel { model | attachRename = Just (AttachmentRename id n) } Nothing -> - noSub ( model, Cmd.none ) + resultModel model Just _ -> - noSub ( { model | attachRename = Nothing }, Cmd.none ) + resultModel { model | attachRename = Nothing } EditAttachNameCancel -> - noSub ( { model | attachRename = Nothing }, Cmd.none ) + resultModel { model | attachRename = Nothing } EditAttachNameSet str -> case model.attachRename of Just m -> - noSub - ( { model | attachRename = Just { m | newName = str } } - , Cmd.none - ) + resultModel + { model | attachRename = Just { m | newName = str } } Nothing -> - noSub ( model, Cmd.none ) + resultModel model EditAttachNameSubmit -> let @@ -1183,7 +1163,7 @@ update key flags inav settings msg model = in case ma of Just m -> - noSub + resultModelCmd ( model , Api.setAttachmentName flags @@ -1193,7 +1173,7 @@ update key flags inav settings msg model = ) Nothing -> - noSub ( { model | attachRename = Nothing }, Cmd.none ) + resultModel { model | attachRename = Nothing } EditAttachNameResp (Ok res) -> if res.success then @@ -1210,25 +1190,23 @@ update key flags inav settings msg model = changeItem i = { i | attachments = List.map changeName i.attachments } in - noSub - ( { model + resultModel + { model | attachRename = Nothing , item = changeItem model.item - } - , Cmd.none - ) + } Nothing -> - noSub ( model, Cmd.none ) + resultModel model else - noSub ( model, Cmd.none ) + resultModel model EditAttachNameResp (Err _) -> - noSub ( model, Cmd.none ) + resultModel model ResetHiddenMsg _ _ -> - noSub ( model, Cmd.none ) + resultModel model UpdateThrottle -> let @@ -1255,18 +1233,18 @@ update key flags inav settings msg model = else if keys == Just Comp.KeyInput.ctrlPoint then case inav.next of Just id -> - noSub ( model_, Page.set key (ItemDetailPage id) ) + resultModelCmd ( model_, Page.set key (ItemDetailPage id) ) Nothing -> - noSub ( model_, Cmd.none ) + resultModel model_ else if keys == Just Comp.KeyInput.ctrlComma then case inav.prev of Just id -> - noSub ( model_, Page.set key (ItemDetailPage id) ) + resultModelCmd ( model_, Page.set key (ItemDetailPage id) ) Nothing -> - noSub ( model_, Cmd.none ) + resultModel model_ else -- withSub because the keypress may be inside the name @@ -1274,7 +1252,7 @@ update key flags inav settings msg model = withSub ( model_, Cmd.none ) ToggleAttachMenu -> - noSub ( { model | attachMenuOpen = not model.attachMenuOpen }, Cmd.none ) + resultModel { model | attachMenuOpen = not model.attachMenuOpen } UiSettingsUpdated -> let @@ -1283,7 +1261,14 @@ update key flags inav settings msg model = | menuOpen = settings.editMenuVisible } in - noSub ( model_, Cmd.none ) + resultModel model_ + + SetLinkTarget lt -> + { model = model + , cmd = Cmd.none + , sub = Sub.none + , linkTarget = lt + } @@ -1419,19 +1404,16 @@ setErrored model fileid = Set.insert fileid model.errored -noSub : ( Model, Cmd Msg ) -> ( Model, Cmd Msg, Sub Msg ) -noSub ( m, c ) = - ( m, c, Sub.none ) - - -withSub : ( Model, Cmd Msg ) -> ( Model, Cmd Msg, Sub Msg ) +withSub : ( Model, Cmd Msg ) -> UpdateResult withSub ( m, c ) = - ( m - , c - , Throttle.ifNeeded - (Time.every 400 (\_ -> UpdateThrottle)) - m.nameSaveThrottle - ) + { model = m + , cmd = c + , sub = + Throttle.ifNeeded + (Time.every 400 (\_ -> UpdateThrottle)) + m.nameSaveThrottle + , linkTarget = Comp.LinkTarget.LinkNone + } resetField : Flags -> String -> (Field -> Result Http.Error BasicResult -> msg) -> Field -> Cmd msg diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm index 04c00406..27eef314 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail/View.elm @@ -2,6 +2,7 @@ module Comp.ItemDetail.View exposing (view) import Api import Api.Model.Attachment exposing (Attachment) +import Api.Model.IdName exposing (IdName) import Comp.AttachmentMeta import Comp.DatePicker import Comp.DetailEdit @@ -11,6 +12,7 @@ import Comp.ItemDetail.AttachmentTabMenu import Comp.ItemDetail.Model exposing (Model, Msg(..), NotesField(..), SaveNameState(..)) import Comp.ItemMail import Comp.KeyInput +import Comp.LinkTarget import Comp.MarkdownInput import Comp.SentMails import Comp.YesNoDimmer @@ -519,13 +521,9 @@ renderItemInfo settings model = [ class "item" , title "Correspondent" ] - [ Icons.correspondentIcon "" - , List.filterMap identity [ model.item.corrOrg, model.item.corrPerson ] - |> List.map .name - |> String.join ", " - |> Util.String.withDefault "(None)" - |> text - ] + (Icons.correspondentIcon "" + :: Comp.LinkTarget.makeCorrLink model.item SetLinkTarget + ) , Data.UiSettings.fieldVisible settings Data.Fields.CorrOrg || Data.UiSettings.fieldVisible settings Data.Fields.CorrPerson ) @@ -535,13 +533,9 @@ renderItemInfo settings model = [ class "item" , title "Concerning" ] - [ Icons.concernedIcon - , List.filterMap identity [ model.item.concPerson, model.item.concEquipment ] - |> List.map .name - |> String.join ", " - |> Util.String.withDefault "(None)" - |> text - ] + (Icons.concernedIcon + :: Comp.LinkTarget.makeConcLink model.item SetLinkTarget + ) , Data.UiSettings.fieldVisible settings Data.Fields.ConcEquip || Data.UiSettings.fieldVisible settings Data.Fields.ConcPerson ) @@ -552,9 +546,7 @@ renderItemInfo settings model = , title "Folder" ] [ Icons.folderIcon "" - , Maybe.map .name model.item.folder - |> Maybe.withDefault "-" - |> text + , Comp.LinkTarget.makeFolderLink model.item SetLinkTarget ] , Data.UiSettings.fieldVisible settings Data.Fields.Folder ) @@ -592,7 +584,7 @@ renderItemInfo settings model = [ text "New!" ] , div [ class "sub header" ] - [ div [ class "ui horizontal bulleted list" ] + [ div [ class "ui horizontal bulleted link list" ] (List.filter Tuple.second [ date , corr @@ -624,14 +616,12 @@ renderTags settings model = [ div [ class "ui right aligned fluid container" ] <| List.map (\t -> - div - [ classList - [ ( "ui tag label", True ) - , ( Data.UiSettings.tagColorString t settings, True ) - ] - ] - [ text t.name + Comp.LinkTarget.makeTagLink + (IdName t.id t.name) + [ ( "ui tag label", True ) + , ( Data.UiSettings.tagColorString t settings, True ) ] + SetLinkTarget ) model.item.tags ] diff --git a/modules/webapp/src/main/elm/Comp/LinkTarget.elm b/modules/webapp/src/main/elm/Comp/LinkTarget.elm new file mode 100644 index 00000000..c9908bb6 --- /dev/null +++ b/modules/webapp/src/main/elm/Comp/LinkTarget.elm @@ -0,0 +1,105 @@ +module Comp.LinkTarget exposing + ( LinkTarget(..) + , makeConcLink + , makeCorrLink + , makeFolderLink + , makeTagLink + ) + +import Api.Model.IdName exposing (IdName) +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (onClick) + + +type LinkTarget + = LinkCorrOrg IdName + | LinkCorrPerson IdName + | LinkConcPerson IdName + | LinkConcEquip IdName + | LinkFolder IdName + | LinkTag IdName + | LinkNone + + +makeCorrLink : + { a | corrOrg : Maybe IdName, corrPerson : Maybe IdName } + -> (LinkTarget -> msg) + -> List (Html msg) +makeCorrLink item tagger = + let + makeOrg idname = + makeLink [] (LinkCorrOrg >> tagger) idname + + makePerson idname = + makeLink [] (LinkCorrPerson >> tagger) idname + in + combine (Maybe.map makeOrg item.corrOrg) (Maybe.map makePerson item.corrPerson) + + +makeConcLink : + { a | concPerson : Maybe IdName, concEquipment : Maybe IdName } + -> (LinkTarget -> msg) + -> List (Html msg) +makeConcLink item tagger = + let + makePerson idname = + makeLink [] (LinkConcPerson >> tagger) idname + + makeEquip idname = + makeLink [] (LinkConcEquip >> tagger) idname + in + combine (Maybe.map makePerson item.concPerson) (Maybe.map makeEquip item.concEquipment) + + +makeFolderLink : + { a | folder : Maybe IdName } + -> (LinkTarget -> msg) + -> Html msg +makeFolderLink item tagger = + let + makeFolder idname = + makeLink [] (LinkFolder >> tagger) idname + in + Maybe.map makeFolder item.folder + |> Maybe.withDefault (text "-") + + +makeTagLink : + IdName + -> List ( String, Bool ) + -> (LinkTarget -> msg) + -> Html msg +makeTagLink tagId classes tagger = + makeLink classes (LinkTag >> tagger) tagId + + + +--- Helpers + + +combine : Maybe (Html msg) -> Maybe (Html msg) -> List (Html msg) +combine ma mb = + case ( ma, mb ) of + ( Just a, Just b ) -> + [ a, text ", ", b ] + + ( Just a, Nothing ) -> + [ a ] + + ( Nothing, Just b ) -> + [ b ] + + ( Nothing, Nothing ) -> + [ text "-" ] + + +makeLink : List ( String, Bool ) -> (IdName -> msg) -> IdName -> Html msg +makeLink classes tagger idname = + a + [ onClick (tagger idname) + , href "#" + , classList classes + ] + [ text idname.name + ] diff --git a/modules/webapp/src/main/elm/Comp/SearchMenu.elm b/modules/webapp/src/main/elm/Comp/SearchMenu.elm index 926ea672..07af0830 100644 --- a/modules/webapp/src/main/elm/Comp/SearchMenu.elm +++ b/modules/webapp/src/main/elm/Comp/SearchMenu.elm @@ -191,6 +191,40 @@ getItemSearch model = } +resetModel : Model -> Model +resetModel model = + let + emptyDropdown dm = + Comp.Dropdown.update (Comp.Dropdown.SetSelection []) dm + |> Tuple.first + + emptyFolder fm = + Comp.FolderSelect.deselect fm + |> Maybe.map (\msg -> Comp.FolderSelect.update msg fm) + |> Maybe.map Tuple.first + |> Maybe.withDefault fm + in + { model + | tagSelection = Comp.TagSelect.emptySelection + , tagSelectModel = Comp.TagSelect.reset model.tagSelectModel + , directionModel = emptyDropdown model.directionModel + , orgModel = emptyDropdown model.orgModel + , corrPersonModel = emptyDropdown model.corrPersonModel + , concPersonModel = emptyDropdown model.concPersonModel + , concEquipmentModel = emptyDropdown model.concEquipmentModel + , folderList = emptyFolder model.folderList + , selectedFolder = Nothing + , inboxCheckbox = False + , fromDate = Nothing + , untilDate = Nothing + , fromDueDate = Nothing + , untilDueDate = Nothing + , nameModel = Nothing + , allNameModel = Nothing + , fulltextModel = Nothing + } + + -- Update @@ -220,6 +254,12 @@ type Msg | ToggleNameHelp | FolderSelectMsg Comp.FolderSelect.Msg | GetFolderResp (Result Http.Error FolderList) + | SetCorrOrg IdName + | SetCorrPerson IdName + | SetConcPerson IdName + | SetConcEquip IdName + | SetFolder IdName + | SetTag String type alias NextState = @@ -237,6 +277,26 @@ update = updateDrop : DD.Model -> Flags -> UiSettings -> Msg -> Model -> NextState updateDrop ddm flags settings msg model = + let + resetAndSet : Msg -> NextState + resetAndSet m = + let + reset = + resetModel model + + set = + updateDrop ddm + flags + settings + m + reset + in + { model = set.model + , cmd = set.cmd + , stateChange = True + , dragDrop = set.dragDrop + } + in case msg of Init -> let @@ -278,11 +338,42 @@ updateDrop ddm flags settings msg model = } ResetForm -> + { model = resetModel model + , cmd = Cmd.none + , stateChange = True + , dragDrop = DD.DragDropData ddm Nothing + } + + SetCorrOrg id -> + resetAndSet (OrgMsg (Comp.Dropdown.SetSelection [ id ])) + + SetCorrPerson id -> + resetAndSet (CorrPersonMsg (Comp.Dropdown.SetSelection [ id ])) + + SetConcPerson id -> + resetAndSet (ConcPersonMsg (Comp.Dropdown.SetSelection [ id ])) + + SetFolder id -> + case Comp.FolderSelect.setSelected id.id model.folderList of + Just lm -> + resetAndSet (FolderSelectMsg lm) + + Nothing -> + { model = model + , cmd = Cmd.none + , stateChange = False + , dragDrop = DD.DragDropData ddm Nothing + } + + SetConcEquip id -> let - next = - update flags settings Init init + equip = + Equipment id.id id.name 0 in - { next | stateChange = True } + resetAndSet (ConcEquipmentMsg (Comp.Dropdown.SetSelection [ equip ])) + + SetTag id -> + resetAndSet (TagSelectMsg (Comp.TagSelect.toggleTag id)) GetTagsResp (Ok tags) -> let diff --git a/modules/webapp/src/main/elm/Comp/TagSelect.elm b/modules/webapp/src/main/elm/Comp/TagSelect.elm index 183610c1..77f11b23 100644 --- a/modules/webapp/src/main/elm/Comp/TagSelect.elm +++ b/modules/webapp/src/main/elm/Comp/TagSelect.elm @@ -5,6 +5,8 @@ module Comp.TagSelect exposing , Selection , emptySelection , init + , reset + , toggleTag , update , updateDrop , viewCats @@ -75,6 +77,19 @@ init sel tags = } +reset : Model -> Model +reset model = + { model + | selectedTags = Dict.empty + , selectedCats = Dict.empty + } + + +toggleTag : String -> Msg +toggleTag id = + ToggleTag id + + sumCategories : List TagCount -> List Category sumCategories tags = let diff --git a/modules/webapp/src/main/elm/Page/Home/Data.elm b/modules/webapp/src/main/elm/Page/Home/Data.elm index dfc22f55..dcd14300 100644 --- a/modules/webapp/src/main/elm/Page/Home/Data.elm +++ b/modules/webapp/src/main/elm/Page/Home/Data.elm @@ -25,6 +25,7 @@ import Comp.FixedDropdown import Comp.ItemCardList import Comp.ItemDetail.EditMenu exposing (SaveNameState(..)) import Comp.ItemDetail.FormChange exposing (FormChange) +import Comp.LinkTarget exposing (LinkTarget) import Comp.SearchMenu import Comp.YesNoDimmer import Data.Flags exposing (Flags) @@ -174,6 +175,7 @@ type Msg | ReplaceChangedItemsResp (Result Http.Error ItemLightList) | DeleteAllResp (Result Http.Error BasicResult) | UiSettingsUpdated + | SetLinkTarget LinkTarget type SearchType diff --git a/modules/webapp/src/main/elm/Page/Home/Update.elm b/modules/webapp/src/main/elm/Page/Home/Update.elm index a4840e25..a57fd172 100644 --- a/modules/webapp/src/main/elm/Page/Home/Update.elm +++ b/modules/webapp/src/main/elm/Page/Home/Update.elm @@ -6,9 +6,11 @@ import Api.Model.ItemLightList exposing (ItemLightList) import Api.Model.ItemSearch import Browser.Navigation as Nav import Comp.FixedDropdown +import Comp.ItemCard import Comp.ItemCardList import Comp.ItemDetail.EditMenu exposing (SaveNameState(..)) import Comp.ItemDetail.FormChange exposing (FormChange(..)) +import Comp.LinkTarget exposing (LinkTarget) import Comp.SearchMenu import Comp.YesNoDimmer import Data.Flags exposing (Flags) @@ -46,6 +48,7 @@ update mId key flags settings msg model = { model | searchOffset = 0 , searchType = defaultSearchType flags + , contentOnlySearch = Nothing } in update mId key flags settings (SearchMenuMsg Comp.SearchMenu.ResetForm) nm @@ -85,6 +88,14 @@ update mId key flags settings msg model = , s2 ) + SetLinkTarget lt -> + case linkTargetMsg lt of + Just m -> + update mId key flags settings m model + + Nothing -> + ( model, Cmd.none, Sub.none ) + ItemCardListMsg m -> let result = @@ -93,6 +104,10 @@ update mId key flags settings msg model = m model.itemListModel + searchMsg = + Maybe.map Util.Update.cmdUnit (linkTargetMsg result.linkTarget) + |> Maybe.withDefault Cmd.none + nextView = case ( model.viewMode, result.selection ) of ( SelectView svm, Data.ItemSelection.Active ids ) -> @@ -107,7 +122,7 @@ update mId key flags settings msg model = , viewMode = nextView , dragDropData = DD.DragDropData result.dragModel Nothing } - , Cmd.batch [ Cmd.map ItemCardListMsg result.cmd ] + , Cmd.batch [ Cmd.map ItemCardListMsg result.cmd, searchMsg ] ) ItemSearchResp scroll (Ok list) -> @@ -642,6 +657,31 @@ doSearch flags settings scroll model = ) +linkTargetMsg : LinkTarget -> Maybe Msg +linkTargetMsg linkTarget = + case linkTarget of + Comp.LinkTarget.LinkNone -> + Nothing + + Comp.LinkTarget.LinkCorrOrg id -> + Just <| SearchMenuMsg (Comp.SearchMenu.SetCorrOrg id) + + Comp.LinkTarget.LinkCorrPerson id -> + Just <| SearchMenuMsg (Comp.SearchMenu.SetCorrPerson id) + + Comp.LinkTarget.LinkConcPerson id -> + Just <| SearchMenuMsg (Comp.SearchMenu.SetConcPerson id) + + Comp.LinkTarget.LinkConcEquip id -> + Just <| SearchMenuMsg (Comp.SearchMenu.SetConcEquip id) + + Comp.LinkTarget.LinkFolder id -> + Just <| SearchMenuMsg (Comp.SearchMenu.SetFolder id) + + Comp.LinkTarget.LinkTag id -> + Just <| SearchMenuMsg (Comp.SearchMenu.SetTag id.id) + + doSearchMore : Flags -> UiSettings -> Model -> ( Model, Cmd Msg ) doSearchMore flags settings model = let diff --git a/modules/webapp/src/main/elm/Page/Home/View.elm b/modules/webapp/src/main/elm/Page/Home/View.elm index 5a506ccc..dd2d3ef1 100644 --- a/modules/webapp/src/main/elm/Page/Home/View.elm +++ b/modules/webapp/src/main/elm/Page/Home/View.elm @@ -300,51 +300,74 @@ viewSearchBar flags model = ] ] [ a - [ class "search-menu-toggle ui blue icon button" + [ classList + [ ( "search-menu-toggle ui icon button", True ) + , ( "primary", not (searchMenuFilled model) ) + , ( "secondary", searchMenuFilled model ) + ] , onClick ToggleSearchMenu , href "#" , title "Open search menu" ] [ i [ class "filter icon" ] [] ] - , div [ class "right fitted item" ] - [ div [ class "ui left icon right action input" ] - [ i - [ classList - [ ( "search link icon", not model.searchInProgress ) - , ( "loading spinner icon", model.searchInProgress ) - ] - , href "#" - , onClick DoSearch - ] - (if hasMoreSearch model && model.searchTypeForm == BasicSearch then - [ i [ class "icons search-corner-icons" ] - [ i [ class "tiny blue circle icon" ] [] + , div [ class "right menu" ] + [ div [ class "fitted item" ] + [ div [ class "ui left icon right action input" ] + [ i + [ classList + [ ( "search link icon", not model.searchInProgress ) + , ( "loading spinner icon", model.searchInProgress ) ] + , href "#" + , onClick DoSearch ] + (if hasMoreSearch model && model.searchTypeForm == BasicSearch then + [ i [ class "icons search-corner-icons" ] + [ i [ class "tiny blue circle icon" ] [] + ] + ] - else + else + [] + ) + , input + [ type_ "text" + , placeholder "Quick Search …" + , onInput SetBasicSearch + , Util.Html.onKeyUpCode KeyUpMsg + , Maybe.map value searchInput + |> Maybe.withDefault (value "") + ] [] - ) - , input - [ type_ "text" - , placeholder "Quick Search …" - , onInput SetBasicSearch - , Util.Html.onKeyUpCode KeyUpMsg - , Maybe.map value searchInput - |> Maybe.withDefault (value "") + , Html.map SearchTypeMsg + (Comp.FixedDropdown.viewStyled searchTypeClass + (Just searchTypeItem) + model.searchTypeDropdown + ) + , a + [ class "ui icon basic button" + , href "#" + , onClick ResetSearch + , title "Reset search form" + ] + [ i [ class "undo icon" ] [] + ] ] - [] - , Html.map SearchTypeMsg - (Comp.FixedDropdown.viewStyled searchTypeClass - (Just searchTypeItem) - model.searchTypeDropdown - ) ] ] ] +searchMenuFilled : Model -> Bool +searchMenuFilled model = + let + is = + Comp.SearchMenu.getItemSearch model.searchMenuModel + in + is /= Api.Model.ItemSearch.empty + + hasMoreSearch : Model -> Bool hasMoreSearch model = let diff --git a/modules/webapp/src/main/elm/Page/ItemDetail/Data.elm b/modules/webapp/src/main/elm/Page/ItemDetail/Data.elm index f1597990..811b9cc0 100644 --- a/modules/webapp/src/main/elm/Page/ItemDetail/Data.elm +++ b/modules/webapp/src/main/elm/Page/ItemDetail/Data.elm @@ -1,9 +1,15 @@ -module Page.ItemDetail.Data exposing (Model, Msg(..), emptyModel) +module Page.ItemDetail.Data exposing + ( Model + , Msg(..) + , UpdateResult + , emptyModel + ) import Api.Model.ItemDetail exposing (ItemDetail) import Browser.Dom as Dom import Comp.ItemDetail import Comp.ItemDetail.Model +import Comp.LinkTarget exposing (LinkTarget) import Http @@ -24,3 +30,11 @@ type Msg | ItemResp (Result Http.Error ItemDetail) | ScrollResult (Result Dom.Error ()) | UiSettingsUpdated + + +type alias UpdateResult = + { model : Model + , cmd : Cmd Msg + , sub : Sub Msg + , linkTarget : LinkTarget + } diff --git a/modules/webapp/src/main/elm/Page/ItemDetail/Update.elm b/modules/webapp/src/main/elm/Page/ItemDetail/Update.elm index 63509826..34fdd34b 100644 --- a/modules/webapp/src/main/elm/Page/ItemDetail/Update.elm +++ b/modules/webapp/src/main/elm/Page/ItemDetail/Update.elm @@ -4,20 +4,22 @@ import Api import Browser.Navigation as Nav import Comp.ItemDetail import Comp.ItemDetail.Model +import Comp.LinkTarget import Data.Flags exposing (Flags) import Data.ItemNav exposing (ItemNav) import Data.UiSettings exposing (UiSettings) -import Page.ItemDetail.Data exposing (Model, Msg(..)) +import Page exposing (Page(..)) +import Page.ItemDetail.Data exposing (Model, Msg(..), UpdateResult) import Scroll import Task -update : Nav.Key -> Flags -> ItemNav -> UiSettings -> Msg -> Model -> ( Model, Cmd Msg, Sub Msg ) +update : Nav.Key -> Flags -> ItemNav -> UiSettings -> Msg -> Model -> UpdateResult update key flags inav settings msg model = case msg of Init id -> let - ( lm, lc, ls ) = + result = Comp.ItemDetail.update key flags inav @@ -28,24 +30,35 @@ update key flags inav settings msg model = task = Scroll.scroll "main-content" 0 0 0 0 in - ( { model | detail = lm } - , Cmd.batch - [ Api.itemDetail flags id ItemResp - , Cmd.map ItemDetailMsg lc - , Task.attempt ScrollResult task - ] - , Sub.map ItemDetailMsg ls - ) + { model = { model | detail = result.model } + , cmd = + Cmd.batch + [ Api.itemDetail flags id ItemResp + , Cmd.map ItemDetailMsg result.cmd + , Task.attempt ScrollResult task + ] + , sub = Sub.map ItemDetailMsg result.sub + , linkTarget = result.linkTarget + } ItemDetailMsg lmsg -> let - ( lm, lc, ls ) = + result = Comp.ItemDetail.update key flags inav settings lmsg model.detail + + pageSwitch = + case result.linkTarget of + Comp.LinkTarget.LinkNone -> + Cmd.none + + _ -> + Page.set key HomePage in - ( { model | detail = lm } - , Cmd.map ItemDetailMsg lc - , Sub.map ItemDetailMsg ls - ) + { model = { model | detail = result.model } + , cmd = Cmd.batch [ pageSwitch, Cmd.map ItemDetailMsg result.cmd ] + , sub = Sub.map ItemDetailMsg result.sub + , linkTarget = result.linkTarget + } ItemResp (Ok item) -> let @@ -55,10 +68,10 @@ update key flags inav settings msg model = update key flags inav settings (ItemDetailMsg lmsg) model ItemResp (Err _) -> - ( model, Cmd.none, Sub.none ) + UpdateResult model Cmd.none Sub.none Comp.LinkTarget.LinkNone ScrollResult _ -> - ( model, Cmd.none, Sub.none ) + UpdateResult model Cmd.none Sub.none Comp.LinkTarget.LinkNone UiSettingsUpdated -> let diff --git a/modules/webapp/src/main/elm/Util/Update.elm b/modules/webapp/src/main/elm/Util/Update.elm index 1d14f4ba..0a135e89 100644 --- a/modules/webapp/src/main/elm/Util/Update.elm +++ b/modules/webapp/src/main/elm/Util/Update.elm @@ -1,4 +1,10 @@ -module Util.Update exposing (andThen1, andThen2) +module Util.Update exposing + ( andThen1 + , andThen2 + , cmdUnit + ) + +import Task andThen1 : List (a -> ( a, Cmd b )) -> a -> ( a, Cmd b ) @@ -36,3 +42,8 @@ andThen2 fs m = in List.foldl update init fs |> combine + + +cmdUnit : a -> Cmd a +cmdUnit a = + Task.perform (\_ -> a) (Task.succeed ()) diff --git a/modules/webapp/src/main/webjar/docspell.css b/modules/webapp/src/main/webjar/docspell.css index ddc5ab3d..3c3ccd00 100644 --- a/modules/webapp/src/main/webjar/docspell.css +++ b/modules/webapp/src/main/webjar/docspell.css @@ -93,15 +93,18 @@ padding: 0.8em; } -.default-layout .ui.card .link.content:hover { - box-shadow: 0 0 0 1px #d4d4d5,0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.15); -} .default-layout .card .card-attachment-nav { position: absolute; left: 4px; top: 4px; z-index: 8; } +.default-layout .multi-select-mode .ui.card { + border: 1px dashed rgba(34,36,38, .8); +} +.default-layout .ui.card:hover { + box-shadow: 0 0 0 1px #d4d4d5,0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.15); +} .default-layout .image.ds-card-image { overflow: auto; }