Set the folder of an item

This commit is contained in:
Eike Kettner 2020-07-11 12:00:19 +02:00
parent 5bde78083a
commit 86443e10a6
8 changed files with 155 additions and 6 deletions

View File

@ -24,6 +24,8 @@ trait OItem[F[_]] {
def setDirection(item: Ident, direction: Direction, collective: Ident): F[AddResult]
def setFolder(item: Ident, folder: Option[Ident], collective: Ident): F[AddResult]
def setCorrOrg(item: Ident, org: Option[Ident], collective: Ident): F[AddResult]
def addCorrOrg(item: Ident, org: OOrganization.OrgAndContacts): F[AddResult]
@ -131,6 +133,16 @@ object OItem {
.attempt
.map(AddResult.fromUpdate)
def setFolder(
item: Ident,
folder: Option[Ident],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateFolder(item, collective, folder))
.attempt
.map(AddResult.fromUpdate)
def setCorrOrg(item: Ident, org: Option[Ident], collective: Ident): F[AddResult] =
store
.transact(RItem.updateCorrOrg(item, collective, org))

View File

@ -1365,6 +1365,31 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/folder:
put:
tags: [ Item ]
summary: Set a folder for this item.
description: |
Updates the folder property for this item to "place" the item
into a folder. If the request contains an empty object or an
`id` property of `null`, the item is moved into the "public"
or "root" folder.
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/id"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/OptionalId"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/corrOrg:
put:
tags: [ Item ]
@ -3167,6 +3192,8 @@ components:
$ref: "#/components/schemas/IdName"
inReplyTo:
$ref: "#/components/schemas/IdName"
folder:
$ref: "#/components/schemas/IdName"
dueDate:
type: integer
format: date-time

View File

@ -85,6 +85,7 @@ trait Conversions {
data.concPerson.map(p => IdName(p.pid, p.name)),
data.concEquip.map(e => IdName(e.eid, e.name)),
data.inReplyTo.map(mkIdName),
data.folder.map(mkIdName),
data.item.dueDate,
data.item.notes,
data.attachments.map((mkAttachment(data) _).tupled).toList,

View File

@ -149,6 +149,13 @@ object ItemRoutes {
resp <- Ok(Conversions.basicResult(res, "Direction updated"))
} yield resp
case req @ PUT -> Root / Ident(id) / "folder" =>
for {
idref <- req.as[OptionalId]
res <- backend.item.setFolder(id, idref.id, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Folder updated"))
} yield resp
case req @ PUT -> Root / Ident(id) / "corrOrg" =>
for {
idref <- req.as[OptionalId]

View File

@ -66,6 +66,7 @@ object QItem {
concPerson: Option[RPerson],
concEquip: Option[REquipment],
inReplyTo: Option[IdRef],
folder: Option[IdRef],
tags: Vector[RTag],
attachments: Vector[(RAttachment, FileMeta)],
sources: Vector[(RAttachmentSource, FileMeta)],
@ -83,10 +84,11 @@ object QItem {
val P1C = RPerson.Columns.all.map(_.prefix("p1"))
val EC = REquipment.Columns.all.map(_.prefix("e"))
val ICC = List(RItem.Columns.id, RItem.Columns.name).map(_.prefix("ref"))
val FC = List(RFolder.Columns.id, RFolder.Columns.name).map(_.prefix("f"))
val cq =
selectSimple(
IC ++ OC ++ P0C ++ P1C ++ EC ++ ICC,
IC ++ OC ++ P0C ++ P1C ++ EC ++ ICC ++ FC,
RItem.table ++ fr"i",
Fragment.empty
) ++
@ -105,6 +107,9 @@ object QItem {
fr"LEFT JOIN" ++ RItem.table ++ fr"ref ON" ++ RItem.Columns.inReplyTo
.prefix("i")
.is(RItem.Columns.id.prefix("ref")) ++
fr"LEFT JOIN" ++ RFolder.table ++ fr"f ON" ++ RItem.Columns.folder
.prefix("i")
.is(RFolder.Columns.id.prefix("f")) ++
fr"WHERE" ++ RItem.Columns.id.prefix("i").is(id)
val q = cq
@ -115,6 +120,7 @@ object QItem {
Option[RPerson],
Option[RPerson],
Option[REquipment],
Option[IdRef],
Option[IdRef]
)
]
@ -132,7 +138,7 @@ object QItem {
arch <- archives
ts <- tags
} yield data.map(d =>
ItemData(d._1, d._2, d._3, d._4, d._5, d._6, ts, att, srcs, arch)
ItemData(d._1, d._2, d._3, d._4, d._5, d._6, d._7, ts, att, srcs, arch)
)
}

View File

@ -82,7 +82,7 @@ object RItem {
val created = Column("created")
val updated = Column("updated")
val notes = Column("notes")
val folder = Column("folder_id")
val folder = Column("folder_id")
val all = List(
id,
cid,
@ -243,7 +243,17 @@ object RItem {
n <- updateRow(
table,
and(cid.is(coll), concEquipment.is(Some(currentEquip))),
commas(concPerson.setTo(None: Option[Ident]), updated.setTo(t))
commas(concEquipment.setTo(None: Option[Ident]), updated.setTo(t))
).update.run
} yield n
def updateFolder(itemId: Ident, coll: Ident, folderId: Option[Ident]): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(cid.is(coll), id.is(itemId)),
commas(folder.setTo(folderId), updated.setTo(t))
).update.run
} yield n

View File

@ -77,6 +77,7 @@ module Api exposing
, setCorrOrg
, setCorrPerson
, setDirection
, setFolder
, setItemDate
, setItemDueDate
, setItemName
@ -1262,6 +1263,16 @@ setDirection flags item dir receive =
}
setFolder : Flags -> String -> OptionalId -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setFolder flags item id receive =
Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/folder"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.OptionalId.encode id)
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
}
setCorrOrg : Flags -> String -> OptionalId -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setCorrOrg flags item id receive =
Http2.authPut

View File

@ -11,6 +11,8 @@ import Api.Model.Attachment exposing (Attachment)
import Api.Model.BasicResult exposing (BasicResult)
import Api.Model.DirectionValue exposing (DirectionValue)
import Api.Model.EquipmentList exposing (EquipmentList)
import Api.Model.FolderItem exposing (FolderItem)
import Api.Model.FolderList exposing (FolderList)
import Api.Model.IdName exposing (IdName)
import Api.Model.ItemDetail exposing (ItemDetail)
import Api.Model.ItemProposals exposing (ItemProposals)
@ -71,6 +73,7 @@ type alias Model =
, corrPersonModel : Comp.Dropdown.Model IdName
, concPersonModel : Comp.Dropdown.Model IdName
, concEquipModel : Comp.Dropdown.Model IdName
, folderModel : Comp.Dropdown.Model IdName
, nameModel : String
, notesModel : Maybe String
, notesField : NotesField
@ -165,6 +168,11 @@ emptyModel =
{ makeOption = \e -> { value = e.id, text = e.name }
, placeholder = ""
}
, folderModel =
Comp.Dropdown.makeSingle
{ makeOption = \e -> { value = e.id, text = e.name }
, placeholder = ""
}
, nameModel = ""
, notesModel = Nothing
, notesField = ViewNotes
@ -268,6 +276,8 @@ type Msg
| EditAttachNameSet String
| EditAttachNameSubmit
| EditAttachNameResp (Result Http.Error BasicResult)
| GetFolderResp (Result Http.Error FolderList)
| FolderDropdownMsg (Comp.Dropdown.Msg IdName)
@ -281,6 +291,7 @@ getOptions flags =
, Api.getOrgLight flags GetOrgResp
, Api.getPersonsLight flags GetPersonResp
, Api.getEquipments flags "" GetEquipResp
, Api.getFolders flags "" False GetFolderResp
]
@ -310,6 +321,16 @@ setDirection flags model =
Cmd.none
setFolder : Flags -> Model -> Maybe IdName -> Cmd Msg
setFolder flags model mref =
let
idref =
Maybe.map .id mref
|> OptionalId
in
Api.setFolder flags model.item.id idref SaveResp
setCorrOrg : Flags -> Model -> Maybe IdName -> Cmd Msg
setCorrOrg flags model mref =
let
@ -523,6 +544,20 @@ update key flags next msg model =
( m7, c7, s7 ) =
update key flags next AddFilesReset m6
( m8, c8, s8 ) =
update key
flags
next
(FolderDropdownMsg
(Comp.Dropdown.SetSelection
(item.folder
|> Maybe.map List.singleton
|> Maybe.withDefault []
)
)
)
m7
proposalCmd =
if item.state == "created" then
Api.getItemProposals flags item.id GetProposalResp
@ -530,7 +565,7 @@ update key flags next msg model =
else
Cmd.none
in
( { m7
( { m8
| item = item
, nameModel = item.name
, notesModel = item.notes
@ -548,11 +583,12 @@ update key flags next msg model =
, c5
, c6
, c7
, c8
, getOptions flags
, proposalCmd
, Api.getSentMails flags item.id SentMailsResp
]
, Sub.batch [ s1, s2, s3, s4, s5, s6, s7 ]
, Sub.batch [ s1, s2, s3, s4, s5, s6, s7, s8 ]
)
SetActiveAttachment pos ->
@ -575,6 +611,26 @@ update key flags next msg model =
else
noSub ( model, Api.itemDetail flags model.item.id GetItemResp )
FolderDropdownMsg m ->
let
( m2, c2 ) =
Comp.Dropdown.update m model.folderModel
newModel =
{ model | folderModel = m2 }
idref =
Comp.Dropdown.getSelected m2 |> List.head
save =
if isDropdownChangeMsg m then
setFolder flags newModel idref
else
Cmd.none
in
noSub ( newModel, Cmd.batch [ save, Cmd.map FolderDropdownMsg c2 ] )
TagDropdownMsg m ->
let
( m2, c2 ) =
@ -827,6 +883,18 @@ update key flags next msg model =
SetDueDateSuggestion date ->
noSub ( model, setDueDate flags model (Just date) )
GetFolderResp (Ok fs) ->
let
opts =
fs.items
|> List.map (\e -> IdName e.id e.name)
|> Comp.Dropdown.SetOptions
in
update key flags next (FolderDropdownMsg opts) model
GetFolderResp (Err _) ->
noSub ( model, Cmd.none )
GetTagsResp (Ok tags) ->
let
tagList =
@ -2082,6 +2150,13 @@ renderEditForm settings model =
]
]
]
, div [ class "field" ]
[ label []
[ Icons.folderIcon "grey"
, text "Folder"
]
, Html.map FolderDropdownMsg (Comp.Dropdown.view settings model.folderModel)
]
, div [ class "field" ]
[ label []
[ Icons.directionIcon "grey"