Merge pull request #415 from eikek/fix-multi-tag-edit

Fix multi tag edit
This commit is contained in:
mergify[bot] 2020-10-31 13:53:29 +00:00 committed by GitHub
commit 17e8fb9b65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 169 additions and 4 deletions

View File

@ -8,7 +8,7 @@ This release contains many bug fixes, thank you all so much for
helping out! There is also a new feature and some more scripts in
tools.
- Edit/delete multiple items at once (#253)
- Edit/delete multiple items at once (#253, #412)
- Show/hide side menus via ui settings (#351)
- Adds two more scripts to the `tools/` section (thanks to
@totti4ever):
@ -36,6 +36,7 @@ tools.
- Routes for managing multiple items:
- `/sec/items/deleteAll`
- `/sec/items/tags`
- `/sec/items/tagsremove`
- `/sec/items/name`
- `/sec/items/folder`
- `/sec/items/direction`

View File

@ -46,6 +46,12 @@ trait OItem[F[_]] {
collective: Ident
): F[UpdateResult]
def removeTagsMultipleItems(
items: NonEmptyList[Ident],
tags: List[String],
collective: Ident
): F[UpdateResult]
/** Toggles tags of the given item. Tags must exist, but can be IDs or names. */
def toggleTags(item: Ident, tags: List[String], collective: Ident): F[UpdateResult]
@ -225,6 +231,29 @@ object OItem {
}
}
def removeTagsMultipleItems(
items: NonEmptyList[Ident],
tags: List[String],
collective: Ident
): F[UpdateResult] =
tags.distinct match {
case Nil => UpdateResult.success.pure[F]
case ws =>
store.transact {
(for {
itemIds <- OptionT
.liftF(RItem.filterItems(items, collective))
.filter(_.nonEmpty)
given <- OptionT.liftF(RTag.findAllByNameOrId(ws, collective))
_ <- OptionT.liftF(
itemIds.traverse(item =>
RTagItem.removeAllTags(item, given.map(_.tagId).toList)
)
)
} yield UpdateResult.success).getOrElse(UpdateResult.notFound)
}
}
def toggleTags(
item: Ident,
tags: List[String],

View File

@ -1945,6 +1945,29 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/items/tagsremove:
post:
tags:
- Item (Multi Edit)
summary: Remove tags from multiple items
description: |
Remove the given tags from all given items.
security:
- authTokenHeader: []
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/ItemsAndRefs"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
put:
tags:
- Item (Multi Edit)

View File

@ -73,6 +73,18 @@ object ItemMultiRoutes {
resp <- Ok(Conversions.basicResult(res, "Tags added."))
} yield resp
case req @ POST -> Root / "tagsremove" =>
for {
json <- req.as[ItemsAndRefs]
items <- readIds[F](json.items)
res <- backend.item.removeTagsMultipleItems(
items,
json.refs,
user.account.collective
)
resp <- Ok(Conversions.basicResult(res, "Tags removed"))
} yield resp
case req @ PUT -> Root / "name" =>
for {
json <- req.as[ItemsAndName]

View File

@ -75,6 +75,7 @@ module Api exposing
, refreshSession
, register
, removeMember
, removeTagsMultiple
, sendMail
, setAttachmentName
, setCollectiveSettings
@ -1342,6 +1343,20 @@ addTagsMultiple flags data receive =
}
removeTagsMultiple :
Flags
-> ItemsAndRefs
-> (Result Http.Error BasicResult -> msg)
-> Cmd msg
removeTagsMultiple flags data receive =
Http2.authPost
{ url = flags.config.baseUrl ++ "/api/v1/sec/items/tagsremove"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.ItemsAndRefs.encode data)
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
}
setNameMultiple :
Flags
-> ItemsAndName

View File

@ -53,6 +53,12 @@ type SaveNameState
| SaveFailed
type TagEditMode
= AddTags
| RemoveTags
| ReplaceTags
type alias Model =
{ tagModel : Comp.Dropdown.Model Tag
, nameModel : String
@ -70,6 +76,7 @@ type alias Model =
, concPersonModel : Comp.Dropdown.Model IdName
, concEquipModel : Comp.Dropdown.Model IdName
, modalEdit : Maybe Comp.DetailEdit.Model
, tagEditMode : TagEditMode
}
@ -82,6 +89,7 @@ type Msg
| RemoveDueDate
| RemoveDate
| ConfirmMsg Bool
| ToggleTagEditMode
| FolderDropdownMsg (Comp.Dropdown.Msg IdName)
| TagDropdownMsg (Comp.Dropdown.Msg Tag)
| DirDropdownMsg (Comp.Dropdown.Msg Direction)
@ -146,6 +154,7 @@ init =
, dueDate = Nothing
, dueDatePicker = Comp.DatePicker.emptyModel
, modalEdit = Nothing
, tagEditMode = AddTags
}
@ -213,19 +222,48 @@ update flags msg model =
newModel =
{ model | tagModel = m2 }
mkChange list =
case model.tagEditMode of
AddTags ->
AddTagChange list
RemoveTags ->
RemoveTagChange list
ReplaceTags ->
ReplaceTagChange list
change =
if isDropdownChangeMsg m then
Comp.Dropdown.getSelected newModel.tagModel
|> Util.List.distinct
|> List.map (\t -> IdName t.id t.name)
|> ReferenceList
|> TagChange
|> mkChange
else
NoFormChange
in
resultNoCmd change newModel
ToggleTagEditMode ->
let
( m2, _ ) =
Comp.Dropdown.update (Comp.Dropdown.SetSelection []) model.tagModel
newModel =
{ model | tagModel = m2 }
in
case model.tagEditMode of
AddTags ->
resultNone { newModel | tagEditMode = RemoveTags }
RemoveTags ->
resultNone { newModel | tagEditMode = ReplaceTags }
ReplaceTags ->
resultNone { newModel | tagEditMode = AddTags }
GetTagsResp (Ok tags) ->
let
tagList =
@ -554,6 +592,28 @@ renderEditForm cfg settings model =
else
span [ class "invisible hidden" ] []
tagModeIcon =
case model.tagEditMode of
AddTags ->
i [ class "grey plus link icon" ] []
RemoveTags ->
i [ class "grey eraser link icon" ] []
ReplaceTags ->
i [ class "grey redo alternate link icon" ] []
tagModeMsg =
case model.tagEditMode of
AddTags ->
"Tags chosen here are *added* to all selected items."
RemoveTags ->
"Tags chosen here are *removed* from all selected items."
ReplaceTags ->
"Tags chosen here *replace* those on selected items."
in
div [ class cfg.menuClass ]
[ div [ class "ui form warning" ]
@ -581,8 +641,17 @@ renderEditForm cfg settings model =
[ label []
[ Icons.tagsIcon "grey"
, text "Tags"
, a
[ class "right-float"
, href "#"
, title "Change tag edit mode"
, onClick ToggleTagEditMode
]
[ tagModeIcon
]
]
, Html.map TagDropdownMsg (Comp.Dropdown.view settings model.tagModel)
, Markdown.toHtml [ class "small-info" ] tagModeMsg
]
, div [ class " field" ]
[ label [] [ text "Name" ]

View File

@ -20,7 +20,9 @@ import Set exposing (Set)
type FormChange
= NoFormChange
| TagChange ReferenceList
| AddTagChange ReferenceList
| ReplaceTagChange ReferenceList
| RemoveTagChange ReferenceList
| FolderChange (Maybe IdName)
| DirectionChange Direction
| OrgChange (Maybe IdName)
@ -45,13 +47,27 @@ multiUpdate flags ids change receive =
Set.toList ids
in
case change of
TagChange tags ->
ReplaceTagChange tags ->
let
data =
ItemsAndRefs items (List.map .id tags.items)
in
Api.setTagsMultiple flags data receive
AddTagChange tags ->
let
data =
ItemsAndRefs items (List.map .id tags.items)
in
Api.addTagsMultiple flags data receive
RemoveTagChange tags ->
let
data =
ItemsAndRefs items (List.map .id tags.items)
in
Api.removeTagsMultiple flags data receive
NameChange name ->
let
data =