Make ItemMerge independent from the action

This commit is contained in:
eikek
2022-03-17 23:25:04 +01:00
parent c7b2a1271a
commit 288ed83b7f
6 changed files with 117 additions and 76 deletions

View File

@ -115,6 +115,7 @@ module Api exposing
, loginSession , loginSession
, logout , logout
, mergeItems , mergeItems
, mergeItemsTask
, moveAttachmentBefore , moveAttachmentBefore
, newInvite , newInvite
, openIdAuthLink , openIdAuthLink
@ -1717,18 +1718,26 @@ getJobQueueStateTask flags =
--- Item (Mulit Edit) --- Item (Mulit Edit)
mergeItemsTask : Flags -> List String -> Task.Task Http.Error BasicResult
mergeItemsTask flags ids =
Http2.authTask
{ url = flags.config.baseUrl ++ "/api/v1/sec/items/merge"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.IdList.encode (IdList ids))
, method = "POST"
, headers = []
, resolver = Http2.jsonResolver Api.Model.BasicResult.decoder
, timeout = Nothing
}
mergeItems : mergeItems :
Flags Flags
-> List String -> List String
-> (Result Http.Error BasicResult -> msg) -> (Result Http.Error BasicResult -> msg)
-> Cmd msg -> Cmd msg
mergeItems flags items receive = mergeItems flags items receive =
Http2.authPost mergeItemsTask flags items |> Task.attempt receive
{ url = flags.config.baseUrl ++ "/api/v1/sec/items/merge"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.IdList.encode (IdList items))
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
}
reprocessMultiple : reprocessMultiple :

View File

@ -36,6 +36,7 @@ import Html5.DragDrop as DD
import Http import Http
import Messages.Comp.ItemMerge exposing (Texts) import Messages.Comp.ItemMerge exposing (Texts)
import Styles as S import Styles as S
import Task exposing (Task)
import Util.CustomField import Util.CustomField
import Util.Item import Util.Item
import Util.List import Util.List
@ -89,18 +90,22 @@ type alias DDMsg =
type FormState type FormState
= FormStateInitial = FormStateInitial
| FormStateHttp Http.Error | FormStateHttp Http.Error
| FormStateMergeSuccessful | FormStateActionSuccessful
| FormStateError String | FormStateError String
| FormStateMergeInProcess | FormStateActionInProcess
--- Update --- Update
type alias Action =
List String -> Task Http.Error BasicResult
type Outcome type Outcome
= OutcomeCancel = OutcomeCancel
| OutcomeMerged | OutcomeActionDone
| OutcomeNotYet | OutcomeNotYet
@ -123,15 +128,15 @@ type Msg
= ItemResp (Result Http.Error ItemLightList) = ItemResp (Result Http.Error ItemLightList)
| ToggleInfoText | ToggleInfoText
| DragDrop (DD.Msg Int Int) | DragDrop (DD.Msg Int Int)
| SubmitMerge | SubmitAction
| CancelMerge | CancelAction
| MergeResp (Result Http.Error BasicResult) | ActionResp (Result Http.Error BasicResult)
| RemoveItem String | RemoveItem String
| MoveItem Int Int | MoveItem Int Int
update : Flags -> Msg -> Model -> UpdateResult update : Flags -> Action -> Msg -> Model -> UpdateResult
update flags msg model = update _ action msg model =
case msg of case msg of
ItemResp (Ok list) -> ItemResp (Ok list) ->
notDoneResult ( init (flatten list), Cmd.none ) notDoneResult ( init (flatten list), Cmd.none )
@ -139,11 +144,11 @@ update flags msg model =
ItemResp (Err err) -> ItemResp (Err err) ->
notDoneResult ( { model | formState = FormStateHttp err }, Cmd.none ) notDoneResult ( { model | formState = FormStateHttp err }, Cmd.none )
MergeResp (Ok result) -> ActionResp (Ok result) ->
if result.success then if result.success then
{ model = { model | formState = FormStateMergeSuccessful } { model = { model | formState = FormStateActionSuccessful }
, cmd = Cmd.none , cmd = Cmd.none
, outcome = OutcomeMerged , outcome = OutcomeActionDone
} }
else else
@ -152,7 +157,7 @@ update flags msg model =
, outcome = OutcomeNotYet , outcome = OutcomeNotYet
} }
MergeResp (Err err) -> ActionResp (Err err) ->
{ model = { model | formState = FormStateHttp err } { model = { model | formState = FormStateHttp err }
, cmd = Cmd.none , cmd = Cmd.none
, outcome = OutcomeNotYet , outcome = OutcomeNotYet
@ -203,17 +208,17 @@ update flags msg model =
in in
notDoneResult ( { model | items = items }, Cmd.none ) notDoneResult ( { model | items = items }, Cmd.none )
SubmitMerge -> SubmitAction ->
let let
ids = ids =
List.map .id model.items List.map .id model.items
in in
notDoneResult notDoneResult
( { model | formState = FormStateMergeInProcess } ( { model | formState = FormStateActionInProcess }
, Api.mergeItems flags ids MergeResp , action ids |> Task.attempt ActionResp
) )
CancelMerge -> CancelAction ->
{ model = model { model = model
, cmd = Cmd.none , cmd = Cmd.none
, outcome = OutcomeCancel , outcome = OutcomeCancel
@ -229,14 +234,26 @@ flatten list =
--- View --- View
view : Texts -> UiSettings -> Model -> Html Msg type alias ViewConfig =
view texts settings model = { infoMessage : String
, warnMessage : String
, actionButton : String
, actionTitle : String
, cancelTitle : String
, actionSuccessful : String
, actionInProcess : String
}
view : Texts -> ViewConfig -> UiSettings -> Model -> Html Msg
view texts cfg settings model =
div [ class "px-2 mb-4" ] div [ class "px-2 mb-4" ]
[ h1 [ class S.header1 ] [ h1 [ class S.header1 ]
[ text texts.title [ text texts.title
, a , a
[ class "ml-2" [ class "ml-2"
, class S.link , class S.link
, classList [ ( "hidden", cfg.infoMessage == "" ) ]
, href "#" , href "#"
, onClick ToggleInfoText , onClick ToggleInfoText
] ]
@ -245,36 +262,37 @@ view texts settings model =
] ]
, p , p
[ class S.infoMessage [ class S.infoMessage
, classList [ ( "hidden", not model.showInfoText ) ] , classList [ ( "hidden", not model.showInfoText || cfg.infoMessage == "" ) ]
] ]
[ text texts.infoText [ text cfg.infoMessage
] ]
, p , p
[ class S.warnMessage [ class S.warnMessage
, class "mt-2" , class "mt-2"
, classList [ ( "hidden", cfg.warnMessage == "" ) ]
] ]
[ text texts.deleteWarn [ text cfg.warnMessage
] ]
, MB.view <| , MB.view <|
{ start = { start =
[ MB.PrimaryButton [ MB.PrimaryButton
{ tagger = SubmitMerge { tagger = SubmitAction
, title = texts.submitMergeTitle , title = cfg.actionTitle
, icon = Just "fa fa-less-than" , icon = Just "fa fa-less-than"
, label = texts.submitMerge , label = cfg.actionButton
} }
, MB.SecondaryButton , MB.SecondaryButton
{ tagger = CancelMerge { tagger = CancelAction
, title = texts.cancelMergeTitle , title = cfg.cancelTitle
, icon = Just "fa fa-times" , icon = Just "fa fa-times"
, label = texts.cancelMerge , label = texts.cancelView
} }
] ]
, end = [] , end = []
, rootClasses = "my-4" , rootClasses = "my-4"
, sticky = True , sticky = True
} }
, renderFormState texts model , renderFormState texts cfg model
, div [ class "flex-col px-2" ] , div [ class "flex-col px-2" ]
(List.indexedMap (itemCard texts settings model) model.items) (List.indexedMap (itemCard texts settings model) model.items)
] ]
@ -494,8 +512,8 @@ mainTagsAndFields2 settings item =
(renderFields ++ renderTags) (renderFields ++ renderTags)
renderFormState : Texts -> Model -> Html Msg renderFormState : Texts -> ViewConfig -> Model -> Html Msg
renderFormState texts model = renderFormState texts cfg model =
case model.formState of case model.formState of
FormStateInitial -> FormStateInitial ->
span [ class "hidden" ] [] span [ class "hidden" ] []
@ -516,18 +534,18 @@ renderFormState texts model =
[ text (texts.httpError err) [ text (texts.httpError err)
] ]
FormStateMergeSuccessful -> FormStateActionSuccessful ->
div div
[ class S.successMessage [ class S.successMessage
, class "my-2" , class "my-2"
] ]
[ text texts.mergeSuccessful [ text cfg.actionSuccessful
] ]
FormStateMergeInProcess -> FormStateActionInProcess ->
Comp.Basic.loadingDimmer Comp.Basic.loadingDimmer
{ active = True { active = True
, label = texts.mergeInProcess , label = cfg.actionInProcess
} }

View File

@ -24,16 +24,9 @@ type alias Texts =
{ basics : Messages.Basics.Texts { basics : Messages.Basics.Texts
, httpError : Http.Error -> String , httpError : Http.Error -> String
, title : String , title : String
, infoText : String
, deleteWarn : String
, formatDateLong : Int -> String , formatDateLong : Int -> String
, formatDateShort : Int -> String , formatDateShort : Int -> String
, submitMerge : String , cancelView : String
, cancelMerge : String
, submitMergeTitle : String
, cancelMergeTitle : String
, mergeSuccessful : String
, mergeInProcess : String
} }
@ -42,16 +35,9 @@ gb tz =
{ basics = Messages.Basics.gb { basics = Messages.Basics.gb
, httpError = Messages.Comp.HttpError.gb , httpError = Messages.Comp.HttpError.gb
, title = "Merge Items" , title = "Merge Items"
, infoText = "When merging items the first item in the list acts as the target. Every other items metadata is copied into the target item. If the property is a single value (like correspondent), it is only set if not already present. Tags, custom fields and attachments are added. The items can be reordered using drag&drop."
, deleteWarn = "Note that all items but the first one is deleted after a successful merge!"
, formatDateLong = Messages.DateFormat.formatDateLong Messages.UiLanguage.English tz , formatDateLong = Messages.DateFormat.formatDateLong Messages.UiLanguage.English tz
, formatDateShort = Messages.DateFormat.formatDateShort Messages.UiLanguage.English tz , formatDateShort = Messages.DateFormat.formatDateShort Messages.UiLanguage.English tz
, submitMerge = "Merge" , cancelView = "Cancel"
, submitMergeTitle = "Merge the documents now"
, cancelMerge = "Cancel"
, cancelMergeTitle = "Back to select view"
, mergeSuccessful = "Items merged successfully"
, mergeInProcess = "Items are merged "
} }
@ -60,16 +46,9 @@ de tz =
{ basics = Messages.Basics.de { basics = Messages.Basics.de
, httpError = Messages.Comp.HttpError.de , httpError = Messages.Comp.HttpError.de
, title = "Dokumente zusammenführen" , title = "Dokumente zusammenführen"
, infoText = "Beim Zusammenführen der Dokumente, wird das erste in der Liste als Zieldokument verwendet. Die Metadaten der anderen Dokumente werden der Reihe nach auf des Zieldokument geschrieben. Metadaten die nur einen Wert haben, werden nur gesetzt falls noch kein Wert existiert. Tags, Benutzerfelder und Anhänge werden zu dem Zieldokument hinzugefügt. Die Einträge können mit Drag&Drop umgeordnet werden."
, deleteWarn = "Bitte beachte, dass nach erfolgreicher Zusammenführung alle anderen Dokumente gelöscht werden!"
, formatDateLong = Messages.DateFormat.formatDateLong Messages.UiLanguage.German tz , formatDateLong = Messages.DateFormat.formatDateLong Messages.UiLanguage.German tz
, formatDateShort = Messages.DateFormat.formatDateShort Messages.UiLanguage.German tz , formatDateShort = Messages.DateFormat.formatDateShort Messages.UiLanguage.German tz
, submitMerge = "Zusammenführen" , cancelView = "Abbrechen"
, submitMergeTitle = "Dokumente jetzt zusammenführen"
, cancelMerge = "Abbrechen"
, cancelMergeTitle = "Zurück zur Auswahl"
, mergeSuccessful = "Die Dokumente wurden erfolgreich zusammengeführt."
, mergeInProcess = "Dokumente werden zusammengeführt"
} }
@ -78,14 +57,7 @@ fr tz =
{ basics = Messages.Basics.fr { basics = Messages.Basics.fr
, httpError = Messages.Comp.HttpError.fr , httpError = Messages.Comp.HttpError.fr
, title = "Fusionner des documents" , title = "Fusionner des documents"
, infoText = "Lors d'une fusion, le premier document sert de cible. Les métadonnées des autres documents sont ajoutées à la cible. Si la propriété est un valeur seule (comme correspondant), ceci est ajouté si pas déjà présent. Tags, champs personnalisés et pièces-jointes sont ajoutés. Les documents peuvent être réordonnés avec le glisser/déposer."
, deleteWarn = "Veuillez noter que tous les documents sont supprimés après une fusion réussie !"
, formatDateLong = Messages.DateFormat.formatDateLong Messages.UiLanguage.French tz , formatDateLong = Messages.DateFormat.formatDateLong Messages.UiLanguage.French tz
, formatDateShort = Messages.DateFormat.formatDateShort Messages.UiLanguage.French tz , formatDateShort = Messages.DateFormat.formatDateShort Messages.UiLanguage.French tz
, submitMerge = "Fusionner" , cancelView = "Annuler"
, submitMergeTitle = "Lancer la fusion"
, cancelMerge = "Annuler"
, cancelMergeTitle = "Annuler la fusion"
, mergeSuccessful = "Documents fusionnés avec succès"
, mergeInProcess = "Fusion en cours ..."
} }

View File

@ -60,6 +60,13 @@ type alias Texts =
, expandCollapseRows : String , expandCollapseRows : String
, bookmarkQuery : String , bookmarkQuery : String
, nothingToBookmark : String , nothingToBookmark : String
, submitMerge : String
, mergeInfoText : String
, mergeDeleteWarn : String
, submitMergeTitle : String
, cancelMergeTitle : String
, mergeSuccessful : String
, mergeInProcess : String
} }
@ -102,6 +109,13 @@ gb tz =
, expandCollapseRows = "Expand/Collapse all" , expandCollapseRows = "Expand/Collapse all"
, bookmarkQuery = "Bookmark query" , bookmarkQuery = "Bookmark query"
, nothingToBookmark = "Nothing selected to bookmark" , nothingToBookmark = "Nothing selected to bookmark"
, submitMerge = "Merge"
, mergeInfoText = "When merging items the first item in the list acts as the target. Every other items metadata is copied into the target item. If the property is a single value (like correspondent), it is only set if not already present. Tags, custom fields and attachments are added. The items can be reordered using drag&drop."
, mergeDeleteWarn = "Note that all items but the first one is deleted after a successful merge!"
, submitMergeTitle = "Merge the documents now"
, cancelMergeTitle = "Back to select view"
, mergeSuccessful = "Items merged successfully"
, mergeInProcess = "Items are merged "
} }
@ -144,6 +158,13 @@ de tz =
, expandCollapseRows = "Alle ein-/ausklappen" , expandCollapseRows = "Alle ein-/ausklappen"
, bookmarkQuery = "Abfrage merken" , bookmarkQuery = "Abfrage merken"
, nothingToBookmark = "Keine Abfrage vorhanden" , nothingToBookmark = "Keine Abfrage vorhanden"
, submitMerge = "Zusammenführen"
, mergeInfoText = "Beim Zusammenführen der Dokumente, wird das erste in der Liste als Zieldokument verwendet. Die Metadaten der anderen Dokumente werden der Reihe nach auf des Zieldokument geschrieben. Metadaten die nur einen Wert haben, werden nur gesetzt falls noch kein Wert existiert. Tags, Benutzerfelder und Anhänge werden zu dem Zieldokument hinzugefügt. Die Einträge können mit Drag&Drop umgeordnet werden."
, mergeDeleteWarn = "Bitte beachte, dass nach erfolgreicher Zusammenführung alle anderen Dokumente gelöscht werden!"
, submitMergeTitle = "Dokumente jetzt zusammenführen"
, cancelMergeTitle = "Zurück zur Auswahl"
, mergeSuccessful = "Die Dokumente wurden erfolgreich zusammengeführt."
, mergeInProcess = "Dokumente werden zusammengeführt"
} }
@ -186,4 +207,11 @@ fr tz =
, expandCollapseRows = "Étendre/Réduire tout" , expandCollapseRows = "Étendre/Réduire tout"
, bookmarkQuery = "Requête de favoris" , bookmarkQuery = "Requête de favoris"
, nothingToBookmark = "Rien n'est sélectionné en favori" , nothingToBookmark = "Rien n'est sélectionné en favori"
, submitMerge = "Fusionner"
, mergeInfoText = "Lors d'une fusion, le premier document sert de cible. Les métadonnées des autres documents sont ajoutées à la cible. Si la propriété est un valeur seule (comme correspondant), ceci est ajouté si pas déjà présent. Tags, champs personnalisés et pièces-jointes sont ajoutés. Les documents peuvent être réordonnés avec le glisser/déposer."
, mergeDeleteWarn = "Veuillez noter que tous les documents sont supprimés après une fusion réussie !"
, submitMergeTitle = "Lancer la fusion"
, cancelMergeTitle = "Annuler la fusion"
, mergeSuccessful = "Documents fusionnés avec succès"
, mergeInProcess = "Fusion en cours ..."
} }

View File

@ -600,8 +600,11 @@ update texts bookmarkId lastViewedItemId env msg model =
case model.viewMode of case model.viewMode of
SelectView svm -> SelectView svm ->
let let
action =
Api.mergeItemsTask env.flags
result = result =
Comp.ItemMerge.update env.flags lmsg svm.mergeModel Comp.ItemMerge.update env.flags action lmsg svm.mergeModel
nextView = nextView =
case result.outcome of case result.outcome of
@ -611,13 +614,13 @@ update texts bookmarkId lastViewedItemId env msg model =
Comp.ItemMerge.OutcomeNotYet -> Comp.ItemMerge.OutcomeNotYet ->
SelectView { svm | mergeModel = result.model } SelectView { svm | mergeModel = result.model }
Comp.ItemMerge.OutcomeMerged -> Comp.ItemMerge.OutcomeActionDone ->
SearchView SearchView
model_ = model_ =
{ model | viewMode = nextView } { model | viewMode = nextView }
in in
if result.outcome == Comp.ItemMerge.OutcomeMerged then if result.outcome == Comp.ItemMerge.OutcomeActionDone then
update texts update texts
bookmarkId bookmarkId
lastViewedItemId lastViewedItemId

View File

@ -129,8 +129,19 @@ itemPublishView texts settings flags svm =
itemMergeView : Texts -> UiSettings -> SelectViewModel -> List (Html Msg) itemMergeView : Texts -> UiSettings -> SelectViewModel -> List (Html Msg)
itemMergeView texts settings svm = itemMergeView texts settings svm =
let
cfg =
{ infoMessage = texts.mergeInfoText
, warnMessage = texts.mergeDeleteWarn
, actionButton = texts.submitMerge
, actionTitle = texts.submitMergeTitle
, cancelTitle = texts.cancelMergeTitle
, actionSuccessful = texts.mergeSuccessful
, actionInProcess = texts.mergeInProcess
}
in
[ Html.map MergeItemsMsg [ Html.map MergeItemsMsg
(Comp.ItemMerge.view texts.itemMerge settings svm.mergeModel) (Comp.ItemMerge.view texts.itemMerge cfg settings svm.mergeModel)
] ]