diff --git a/modules/webapp/src/main/elm/Api.elm b/modules/webapp/src/main/elm/Api.elm index e51c15b4..a9da28dd 100644 --- a/modules/webapp/src/main/elm/Api.elm +++ b/modules/webapp/src/main/elm/Api.elm @@ -14,6 +14,7 @@ module Api exposing , addDashboard , addMember , addRelatedItems + , addRelatedItemsTask , addShare , addTag , addTagsMultiple @@ -3044,6 +3045,25 @@ addRelatedItems flags data receive = } +addRelatedItemsTask : Flags -> List String -> Task.Task Http.Error BasicResult +addRelatedItemsTask flags ids = + let + itemData = + { item = List.head ids |> Maybe.withDefault "" + , related = List.tail ids |> Maybe.withDefault [] + } + in + Http2.authTask + { url = flags.config.baseUrl ++ "/api/v1/sec/itemlink/addAll" + , account = getAccount flags + , body = Http.jsonBody (Api.Model.ItemLinkData.encode itemData) + , method = "POST" + , headers = [] + , resolver = Http2.jsonResolver Api.Model.BasicResult.decoder + , timeout = Nothing + } + + removeRelatedItems : Flags -> ItemLinkData -> (Result Http.Error BasicResult -> msg) -> Cmd msg removeRelatedItems flags data receive = Http2.authPost diff --git a/modules/webapp/src/main/elm/Comp/ItemLinkForm.elm b/modules/webapp/src/main/elm/Comp/ItemLinkForm.elm index 924867da..bc525ddb 100644 --- a/modules/webapp/src/main/elm/Comp/ItemLinkForm.elm +++ b/modules/webapp/src/main/elm/Comp/ItemLinkForm.elm @@ -1,3 +1,10 @@ +{- + Copyright 2020 Eike K. & Contributors + + SPDX-License-Identifier: AGPL-3.0-or-later +-} + + module Comp.ItemLinkForm exposing (Model, Msg, emptyModel, init, update, view) import Api diff --git a/modules/webapp/src/main/elm/Comp/ItemMerge.elm b/modules/webapp/src/main/elm/Comp/ItemMerge.elm index 52241a1e..55e823d7 100644 --- a/modules/webapp/src/main/elm/Comp/ItemMerge.elm +++ b/modules/webapp/src/main/elm/Comp/ItemMerge.elm @@ -235,9 +235,11 @@ flatten list = type alias ViewConfig = - { infoMessage : String + { title : String + , infoMessage : String , warnMessage : String , actionButton : String + , actionIcon : String , actionTitle : String , cancelTitle : String , actionSuccessful : String @@ -249,7 +251,7 @@ view : Texts -> ViewConfig -> UiSettings -> Model -> Html Msg view texts cfg settings model = div [ class "px-2 mb-4" ] [ h1 [ class S.header1 ] - [ text texts.title + [ text cfg.title , a [ class "ml-2" , class S.link @@ -278,7 +280,7 @@ view texts cfg settings model = [ MB.PrimaryButton { tagger = SubmitAction , title = cfg.actionTitle - , icon = Just "fa fa-less-than" + , icon = Just cfg.actionIcon , label = cfg.actionButton } , MB.SecondaryButton diff --git a/modules/webapp/src/main/elm/Comp/ItemSearchInput.elm b/modules/webapp/src/main/elm/Comp/ItemSearchInput.elm index 4777d3f4..6fe83107 100644 --- a/modules/webapp/src/main/elm/Comp/ItemSearchInput.elm +++ b/modules/webapp/src/main/elm/Comp/ItemSearchInput.elm @@ -1,3 +1,10 @@ +{- + Copyright 2020 Eike K. & Contributors + + SPDX-License-Identifier: AGPL-3.0-or-later +-} + + module Comp.ItemSearchInput exposing (Config, Model, Msg, defaultConfig, hasFocus, init, isSearching, update, view) import Api diff --git a/modules/webapp/src/main/elm/Data/Icons.elm b/modules/webapp/src/main/elm/Data/Icons.elm index 2a769a37..236390a7 100644 --- a/modules/webapp/src/main/elm/Data/Icons.elm +++ b/modules/webapp/src/main/elm/Data/Icons.elm @@ -47,6 +47,7 @@ module Data.Icons exposing , folderIcon , gotifyIcon , itemDatesIcon + , linkItems , matrixIcon , metadata , metadataIcon @@ -150,6 +151,11 @@ share = "fa fa-share-alt" +linkItems : String +linkItems = + "fa fa-link" + + shareIcon : String -> Html msg shareIcon classes = i [ class (classes ++ " " ++ share) ] [] diff --git a/modules/webapp/src/main/elm/Messages/Comp/ItemLinkForm.elm b/modules/webapp/src/main/elm/Messages/Comp/ItemLinkForm.elm index b460252e..640fae9e 100644 --- a/modules/webapp/src/main/elm/Messages/Comp/ItemLinkForm.elm +++ b/modules/webapp/src/main/elm/Messages/Comp/ItemLinkForm.elm @@ -1,3 +1,10 @@ +{- + Copyright 2020 Eike K. & Contributors + + SPDX-License-Identifier: AGPL-3.0-or-later +-} + + module Messages.Comp.ItemLinkForm exposing (Texts, de, fr, gb) import Data.Direction exposing (Direction) diff --git a/modules/webapp/src/main/elm/Messages/Comp/ItemMerge.elm b/modules/webapp/src/main/elm/Messages/Comp/ItemMerge.elm index 20e725bc..935b8202 100644 --- a/modules/webapp/src/main/elm/Messages/Comp/ItemMerge.elm +++ b/modules/webapp/src/main/elm/Messages/Comp/ItemMerge.elm @@ -23,7 +23,6 @@ import Messages.UiLanguage type alias Texts = { basics : Messages.Basics.Texts , httpError : Http.Error -> String - , title : String , formatDateLong : Int -> String , formatDateShort : Int -> String , cancelView : String @@ -34,7 +33,6 @@ gb : TimeZone -> Texts gb tz = { basics = Messages.Basics.gb , httpError = Messages.Comp.HttpError.gb - , title = "Merge Items" , formatDateLong = Messages.DateFormat.formatDateLong Messages.UiLanguage.English tz , formatDateShort = Messages.DateFormat.formatDateShort Messages.UiLanguage.English tz , cancelView = "Cancel" @@ -45,7 +43,6 @@ de : TimeZone -> Texts de tz = { basics = Messages.Basics.de , httpError = Messages.Comp.HttpError.de - , title = "Dokumente zusammenführen" , formatDateLong = Messages.DateFormat.formatDateLong Messages.UiLanguage.German tz , formatDateShort = Messages.DateFormat.formatDateShort Messages.UiLanguage.German tz , cancelView = "Abbrechen" @@ -56,7 +53,6 @@ fr : TimeZone -> Texts fr tz = { basics = Messages.Basics.fr , httpError = Messages.Comp.HttpError.fr - , title = "Fusionner des documents" , formatDateLong = Messages.DateFormat.formatDateLong Messages.UiLanguage.French tz , formatDateShort = Messages.DateFormat.formatDateShort Messages.UiLanguage.French tz , cancelView = "Annuler" diff --git a/modules/webapp/src/main/elm/Messages/Comp/ItemSearchInput.elm b/modules/webapp/src/main/elm/Messages/Comp/ItemSearchInput.elm index 2fe5d23f..04bb10e7 100644 --- a/modules/webapp/src/main/elm/Messages/Comp/ItemSearchInput.elm +++ b/modules/webapp/src/main/elm/Messages/Comp/ItemSearchInput.elm @@ -1,3 +1,10 @@ +{- + Copyright 2020 Eike K. & Contributors + + SPDX-License-Identifier: AGPL-3.0-or-later +-} + + module Messages.Comp.ItemSearchInput exposing (Texts, de, fr, gb) import Http diff --git a/modules/webapp/src/main/elm/Messages/Page/Search.elm b/modules/webapp/src/main/elm/Messages/Page/Search.elm index c1504f03..3997ae99 100644 --- a/modules/webapp/src/main/elm/Messages/Page/Search.elm +++ b/modules/webapp/src/main/elm/Messages/Page/Search.elm @@ -67,6 +67,15 @@ type alias Texts = , cancelMergeTitle : String , mergeSuccessful : String , mergeInProcess : String + , mergeHeader : String + , linkItemsTitle : Int -> String + , linkItemsMessage : String + , submitLinkItems : String + , submitLinkItemsTitle : String + , cancelLinkItemsTitle : String + , linkItemsSuccessful : String + , linkItemsInProcess : String + , linkItemsHeader : String } @@ -116,6 +125,15 @@ gb tz = , cancelMergeTitle = "Back to select view" , mergeSuccessful = "Items merged successfully" , mergeInProcess = "Items are merged …" + , linkItemsTitle = \n -> "Link " ++ String.fromInt n ++ " items" + , linkItemsMessage = "There must be at least 2 items in the list. The first is the target item and all remaining are added to its related items list." + , submitLinkItems = "Link" + , submitLinkItemsTitle = "" + , cancelLinkItemsTitle = "" + , linkItemsSuccessful = "Linking items successful" + , linkItemsInProcess = "Linking items ..." + , mergeHeader = "Merge Items" + , linkItemsHeader = "Link Items" } @@ -165,6 +183,15 @@ de tz = , cancelMergeTitle = "Zurück zur Auswahl" , mergeSuccessful = "Die Dokumente wurden erfolgreich zusammengeführt." , mergeInProcess = "Dokumente werden zusammengeführt…" + , linkItemsTitle = \n -> String.fromInt n ++ " Dokumente verknüpfen" + , linkItemsMessage = "Die Liste muss mindestens 2 Dokumenta haben. Das erste Dokument erhält alle folgenden als verknüpfte Dokumente." + , submitLinkItems = "Verknüpfen" + , submitLinkItemsTitle = "" + , cancelLinkItemsTitle = "" + , linkItemsSuccessful = "Das Verknüpfen war erflogreich" + , linkItemsInProcess = "Dokumente werden verknüpft ..." + , mergeHeader = "Dokumente zusammenführen" + , linkItemsHeader = "Dokument verknüpfen" } @@ -214,4 +241,13 @@ fr tz = , cancelMergeTitle = "Annuler la fusion" , mergeSuccessful = "Documents fusionnés avec succès" , mergeInProcess = "Fusion en cours ..." + , linkItemsTitle = \n -> String.fromInt n ++ " Lier des documents" + , linkItemsMessage = "La liste doit comporter au moins deux documents. Le premier document reçoit tous les documents suivants en tant que documents liés." + , submitLinkItems = "Relier" + , submitLinkItemsTitle = "" + , cancelLinkItemsTitle = "" + , linkItemsSuccessful = "L'association a été un succès" + , linkItemsInProcess = "Relier en cours ..." + , mergeHeader = "Fusionner des documents" + , linkItemsHeader = "Lier des documents" } diff --git a/modules/webapp/src/main/elm/Page/Search/Data.elm b/modules/webapp/src/main/elm/Page/Search/Data.elm index 6679ea77..9ae4d838 100644 --- a/modules/webapp/src/main/elm/Page/Search/Data.elm +++ b/modules/webapp/src/main/elm/Page/Search/Data.elm @@ -7,6 +7,7 @@ module Page.Search.Data exposing ( ConfirmModalValue(..) + , ItemMergeModel(..) , Model , Msg(..) , SearchParam @@ -88,19 +89,24 @@ type alias SelectViewModel = { action : SelectActionMode , confirmModal : Maybe ConfirmModalValue , editModel : Comp.ItemDetail.MultiEditMenu.Model - , mergeModel : Comp.ItemMerge.Model + , mergeModel : ItemMergeModel , publishModel : Comp.PublishItems.Model , saveNameState : SaveNameState , saveCustomFieldState : Set String } +type ItemMergeModel + = MergeItems Comp.ItemMerge.Model + | LinkItems Comp.ItemMerge.Model + + initSelectViewModel : Flags -> SelectViewModel initSelectViewModel flags = { action = NoneAction , confirmModal = Nothing , editModel = Comp.ItemDetail.MultiEditMenu.init - , mergeModel = Comp.ItemMerge.init [] + , mergeModel = MergeItems (Comp.ItemMerge.init []) , publishModel = Tuple.first (Comp.PublishItems.init flags) , saveNameState = SaveSuccess , saveCustomFieldState = Set.empty @@ -221,7 +227,7 @@ type Msg | ReprocessSelectedConfirmed | ClientSettingsSaveResp (Result Http.Error BasicResult) | RemoveItem String - | MergeSelectedItems + | MergeSelectedItems (Comp.ItemMerge.Model -> ItemMergeModel) | MergeItemsMsg Comp.ItemMerge.Msg | PublishSelectedItems | PublishItemsMsg Comp.PublishItems.Msg diff --git a/modules/webapp/src/main/elm/Page/Search/Update.elm b/modules/webapp/src/main/elm/Page/Search/Update.elm index 3895d359..c8f53d60 100644 --- a/modules/webapp/src/main/elm/Page/Search/Update.elm +++ b/modules/webapp/src/main/elm/Page/Search/Update.elm @@ -555,7 +555,7 @@ update texts bookmarkId lastViewedItemId env msg model = _ -> resultModelCmd env.selectedItems ( model, Cmd.none ) - MergeSelectedItems -> + MergeSelectedItems createModel -> case model.viewMode of SelectView svm -> if svm.action == MergeSelected then @@ -565,7 +565,7 @@ update texts bookmarkId lastViewedItemId env msg model = SelectView { svm | action = NoneAction - , mergeModel = Comp.ItemMerge.init [] + , mergeModel = createModel <| Comp.ItemMerge.init [] } } , Cmd.none @@ -584,7 +584,7 @@ update texts bookmarkId lastViewedItemId env msg model = SelectView { svm | action = MergeSelected - , mergeModel = mm + , mergeModel = createModel mm } } , Cmd.map MergeItemsMsg mc @@ -600,11 +600,16 @@ update texts bookmarkId lastViewedItemId env msg model = case model.viewMode of SelectView svm -> let - action = - Api.mergeItemsTask env.flags + ( mergeModel, createModel, action ) = + case svm.mergeModel of + MergeItems a -> + ( a, MergeItems, Api.mergeItemsTask env.flags ) + + LinkItems a -> + ( a, LinkItems, Api.addRelatedItemsTask env.flags ) result = - Comp.ItemMerge.update env.flags action lmsg svm.mergeModel + Comp.ItemMerge.update env.flags action lmsg mergeModel nextView = case result.outcome of @@ -612,7 +617,7 @@ update texts bookmarkId lastViewedItemId env msg model = SelectView { svm | action = NoneAction } Comp.ItemMerge.OutcomeNotYet -> - SelectView { svm | mergeModel = result.model } + SelectView { svm | mergeModel = createModel result.model } Comp.ItemMerge.OutcomeActionDone -> SearchView diff --git a/modules/webapp/src/main/elm/Page/Search/View2.elm b/modules/webapp/src/main/elm/Page/Search/View2.elm index aa5d6ee9..4bdfe151 100644 --- a/modules/webapp/src/main/elm/Page/Search/View2.elm +++ b/modules/webapp/src/main/elm/Page/Search/View2.elm @@ -130,7 +130,7 @@ itemPublishView texts settings flags svm = itemMergeView : Texts -> UiSettings -> SelectViewModel -> List (Html Msg) itemMergeView texts settings svm = let - cfg = + cfgMerge = { infoMessage = texts.mergeInfoText , warnMessage = texts.mergeDeleteWarn , actionButton = texts.submitMerge @@ -138,10 +138,32 @@ itemMergeView texts settings svm = , cancelTitle = texts.cancelMergeTitle , actionSuccessful = texts.mergeSuccessful , actionInProcess = texts.mergeInProcess + , title = texts.mergeHeader + , actionIcon = "fa fa-less-than" } + + cfgLink = + { infoMessage = "" + , warnMessage = texts.linkItemsMessage + , actionButton = texts.submitLinkItems + , actionTitle = texts.submitLinkItemsTitle + , cancelTitle = texts.cancelLinkItemsTitle + , actionSuccessful = texts.linkItemsSuccessful + , actionInProcess = texts.linkItemsInProcess + , title = texts.linkItemsHeader + , actionIcon = "fa fa-link" + } + + ( mergeModel, cfg ) = + case svm.mergeModel of + MergeItems a -> + ( a, cfgMerge ) + + LinkItems a -> + ( a, cfgLink ) in [ Html.map MergeItemsMsg - (Comp.ItemMerge.view texts.itemMerge cfg settings svm.mergeModel) + (Comp.ItemMerge.view texts.itemMerge cfg settings mergeModel) ] @@ -496,7 +518,7 @@ editMenuBar texts model selectedItems svm = ] } , MB.CustomButton - { tagger = MergeSelectedItems + { tagger = MergeSelectedItems MergeItems , label = "" , icon = Just "fa fa-less-than" , title = texts.mergeItemsTitle selectCount @@ -517,6 +539,17 @@ editMenuBar texts model selectedItems svm = , ( "hidden", model.searchMenuModel.searchMode == Data.SearchMode.Trashed ) ] } + , MB.CustomButton + { tagger = MergeSelectedItems LinkItems + , label = "" + , icon = Just Icons.linkItems + , title = texts.linkItemsTitle selectCount + , inputClass = + [ ( btnStyle, True ) + , ( "bg-gray-200 dark:bg-slate-600", svm.action == PublishSelected ) + , ( "hidden", model.searchMenuModel.searchMode == Data.SearchMode.Trashed ) + ] + } ] , end = [ MB.CustomButton