Merge pull request #143 from eikek/add-data-while-edit-item

Add data while edit item
This commit is contained in:
eikek
2020-06-12 12:11:43 +02:00
committed by GitHub
11 changed files with 1311 additions and 257 deletions

View File

@ -43,18 +43,30 @@ trait OItem[F[_]] {
collective: Ident collective: Ident
): F[Option[AttachmentArchiveData[F]]] ): F[Option[AttachmentArchiveData[F]]]
/** Sets the given tags (removing all existing ones). */
def setTags(item: Ident, tagIds: List[Ident], collective: Ident): F[AddResult] def setTags(item: Ident, tagIds: List[Ident], collective: Ident): F[AddResult]
/** Create a new tag and add it to the item. */
def addNewTag(item: Ident, tag: RTag): F[AddResult]
def setDirection(item: Ident, direction: Direction, collective: Ident): F[AddResult] def setDirection(item: Ident, direction: Direction, collective: Ident): F[AddResult]
def setCorrOrg(item: Ident, org: 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]
def setCorrPerson(item: Ident, person: Option[Ident], collective: Ident): F[AddResult] def setCorrPerson(item: Ident, person: Option[Ident], collective: Ident): F[AddResult]
def addCorrPerson(item: Ident, person: OOrganization.PersonAndContacts): F[AddResult]
def setConcPerson(item: Ident, person: Option[Ident], collective: Ident): F[AddResult] def setConcPerson(item: Ident, person: Option[Ident], collective: Ident): F[AddResult]
def addConcPerson(item: Ident, person: OOrganization.PersonAndContacts): F[AddResult]
def setConcEquip(item: Ident, equip: Option[Ident], collective: Ident): F[AddResult] def setConcEquip(item: Ident, equip: Option[Ident], collective: Ident): F[AddResult]
def addConcEquip(item: Ident, equip: REquipment): F[AddResult]
def setNotes(item: Ident, notes: Option[String], collective: Ident): F[AddResult] def setNotes(item: Ident, notes: Option[String], collective: Ident): F[AddResult]
def setName(item: Ident, notes: String, collective: Ident): F[AddResult] def setName(item: Ident, notes: String, collective: Ident): F[AddResult]
@ -132,220 +144,334 @@ object OItem {
} }
def apply[F[_]: Effect](store: Store[F]): Resource[F, OItem[F]] = def apply[F[_]: Effect](store: Store[F]): Resource[F, OItem[F]] =
Resource.pure[F, OItem[F]](new OItem[F] { for {
otag <- OTag(store)
oorg <- OOrganization(store)
oequip <- OEquipment(store)
oitem <- Resource.pure[F, OItem[F]](new OItem[F] {
def moveAttachmentBefore(
itemId: Ident,
source: Ident,
target: Ident
): F[AddResult] =
store
.transact(QItem.moveAttachmentBefore(itemId, source, target))
.attempt
.map(AddResult.fromUpdate)
def moveAttachmentBefore( def findItem(id: Ident, collective: Ident): F[Option[ItemData]] =
itemId: Ident, store
source: Ident, .transact(QItem.findItem(id))
target: Ident .map(opt => opt.flatMap(_.filterCollective(collective)))
): F[AddResult] =
store
.transact(QItem.moveAttachmentBefore(itemId, source, target))
.attempt
.map(AddResult.fromUpdate)
def findItem(id: Ident, collective: Ident): F[Option[ItemData]] = def findItems(q: Query, batch: Batch): F[Vector[ListItem]] =
store store
.transact(QItem.findItem(id)) .transact(QItem.findItems(q, batch).take(batch.limit.toLong))
.map(opt => opt.flatMap(_.filterCollective(collective))) .compile
.toVector
def findItems(q: Query, batch: Batch): F[Vector[ListItem]] = def findItemsWithTags(q: Query, batch: Batch): F[Vector[ListItemWithTags]] =
store store
.transact(QItem.findItems(q, batch).take(batch.limit.toLong)) .transact(QItem.findItemsWithTags(q, batch).take(batch.limit.toLong))
.compile .compile
.toVector .toVector
def findItemsWithTags(q: Query, batch: Batch): F[Vector[ListItemWithTags]] = def findAttachment(id: Ident, collective: Ident): F[Option[AttachmentData[F]]] =
store store
.transact(QItem.findItemsWithTags(q, batch).take(batch.limit.toLong)) .transact(RAttachment.findByIdAndCollective(id, collective))
.compile .flatMap({
.toVector case Some(ra) =>
makeBinaryData(ra.fileId) { m =>
AttachmentData[F](
ra,
m,
store.bitpeace.fetchData2(RangeDef.all)(Stream.emit(m))
)
}
def findAttachment(id: Ident, collective: Ident): F[Option[AttachmentData[F]]] = case None =>
store (None: Option[AttachmentData[F]]).pure[F]
.transact(RAttachment.findByIdAndCollective(id, collective)) })
.flatMap({
case Some(ra) => def findAttachmentSource(
makeBinaryData(ra.fileId) { m => id: Ident,
AttachmentData[F]( collective: Ident
ra, ): F[Option[AttachmentSourceData[F]]] =
m, store
store.bitpeace.fetchData2(RangeDef.all)(Stream.emit(m)) .transact(RAttachmentSource.findByIdAndCollective(id, collective))
.flatMap({
case Some(ra) =>
makeBinaryData(ra.fileId) { m =>
AttachmentSourceData[F](
ra,
m,
store.bitpeace.fetchData2(RangeDef.all)(Stream.emit(m))
)
}
case None =>
(None: Option[AttachmentSourceData[F]]).pure[F]
})
def findAttachmentArchive(
id: Ident,
collective: Ident
): F[Option[AttachmentArchiveData[F]]] =
store
.transact(RAttachmentArchive.findByIdAndCollective(id, collective))
.flatMap({
case Some(ra) =>
makeBinaryData(ra.fileId) { m =>
AttachmentArchiveData[F](
ra,
m,
store.bitpeace.fetchData2(RangeDef.all)(Stream.emit(m))
)
}
case None =>
(None: Option[AttachmentArchiveData[F]]).pure[F]
})
private def makeBinaryData[A](fileId: Ident)(f: FileMeta => A): F[Option[A]] =
store.bitpeace
.get(fileId.id)
.unNoneTerminate
.compile
.last
.map(
_.map(m => f(m))
)
def setTags(item: Ident, tagIds: List[Ident], collective: Ident): F[AddResult] = {
val db = for {
cid <- RItem.getCollective(item)
nd <-
if (cid.contains(collective)) RTagItem.deleteItemTags(item)
else 0.pure[ConnectionIO]
ni <-
if (tagIds.nonEmpty && cid.contains(collective))
RTagItem.insertItemTags(item, tagIds)
else 0.pure[ConnectionIO]
} yield nd + ni
store.transact(db).attempt.map(AddResult.fromUpdate)
}
def addNewTag(item: Ident, tag: RTag): F[AddResult] =
(for {
_ <- OptionT(store.transact(RItem.getCollective(item)))
.filter(_ == tag.collective)
addres <- OptionT.liftF(otag.add(tag))
_ <- addres match {
case AddResult.Success =>
OptionT.liftF(
store.transact(RTagItem.insertItemTags(item, List(tag.tagId)))
) )
} case AddResult.EntityExists(_) =>
OptionT.pure[F](0)
case AddResult.Failure(_) =>
OptionT.pure[F](0)
}
} yield addres)
.getOrElse(AddResult.Failure(new Exception("Collective mismatch")))
case None => def setDirection(
(None: Option[AttachmentData[F]]).pure[F] item: Ident,
}) direction: Direction,
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateDirection(item, collective, direction))
.attempt
.map(AddResult.fromUpdate)
def findAttachmentSource( def setCorrOrg(item: Ident, org: Option[Ident], collective: Ident): F[AddResult] =
id: Ident, store
collective: Ident .transact(RItem.updateCorrOrg(item, collective, org))
): F[Option[AttachmentSourceData[F]]] = .attempt
store .map(AddResult.fromUpdate)
.transact(RAttachmentSource.findByIdAndCollective(id, collective))
.flatMap({ def addCorrOrg(item: Ident, org: OOrganization.OrgAndContacts): F[AddResult] =
case Some(ra) => (for {
makeBinaryData(ra.fileId) { m => _ <- OptionT(store.transact(RItem.getCollective(item)))
AttachmentSourceData[F]( .filter(_ == org.org.cid)
ra, addres <- OptionT.liftF(oorg.addOrg(org))
m, _ <- addres match {
store.bitpeace.fetchData2(RangeDef.all)(Stream.emit(m)) case AddResult.Success =>
OptionT.liftF(
store.transact(
RItem.updateCorrOrg(item, org.org.cid, Some(org.org.oid))
)
) )
} case AddResult.EntityExists(_) =>
OptionT.pure[F](0)
case AddResult.Failure(_) =>
OptionT.pure[F](0)
}
} yield addres)
.getOrElse(AddResult.Failure(new Exception("Collective mismatch")))
case None => def setCorrPerson(
(None: Option[AttachmentSourceData[F]]).pure[F] item: Ident,
}) person: Option[Ident],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateCorrPerson(item, collective, person))
.attempt
.map(AddResult.fromUpdate)
def findAttachmentArchive( def addCorrPerson(
id: Ident, item: Ident,
collective: Ident person: OOrganization.PersonAndContacts
): F[Option[AttachmentArchiveData[F]]] = ): F[AddResult] =
store (for {
.transact(RAttachmentArchive.findByIdAndCollective(id, collective)) _ <- OptionT(store.transact(RItem.getCollective(item)))
.flatMap({ .filter(_ == person.person.cid)
case Some(ra) => addres <- OptionT.liftF(oorg.addPerson(person))
makeBinaryData(ra.fileId) { m => _ <- addres match {
AttachmentArchiveData[F]( case AddResult.Success =>
ra, OptionT.liftF(
m, store.transact(
store.bitpeace.fetchData2(RangeDef.all)(Stream.emit(m)) RItem
.updateCorrPerson(item, person.person.cid, Some(person.person.pid))
)
) )
} case AddResult.EntityExists(_) =>
OptionT.pure[F](0)
case AddResult.Failure(_) =>
OptionT.pure[F](0)
}
} yield addres)
.getOrElse(AddResult.Failure(new Exception("Collective mismatch")))
case None => def setConcPerson(
(None: Option[AttachmentArchiveData[F]]).pure[F] item: Ident,
}) person: Option[Ident],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateConcPerson(item, collective, person))
.attempt
.map(AddResult.fromUpdate)
private def makeBinaryData[A](fileId: Ident)(f: FileMeta => A): F[Option[A]] = def addConcPerson(
store.bitpeace item: Ident,
.get(fileId.id) person: OOrganization.PersonAndContacts
.unNoneTerminate ): F[AddResult] =
.compile (for {
.last _ <- OptionT(store.transact(RItem.getCollective(item)))
.map( .filter(_ == person.person.cid)
_.map(m => f(m)) addres <- OptionT.liftF(oorg.addPerson(person))
) _ <- addres match {
case AddResult.Success =>
OptionT.liftF(
store.transact(
RItem
.updateConcPerson(item, person.person.cid, Some(person.person.pid))
)
)
case AddResult.EntityExists(_) =>
OptionT.pure[F](0)
case AddResult.Failure(_) =>
OptionT.pure[F](0)
}
} yield addres)
.getOrElse(AddResult.Failure(new Exception("Collective mismatch")))
def setTags(item: Ident, tagIds: List[Ident], collective: Ident): F[AddResult] = { def setConcEquip(
val db = for { item: Ident,
cid <- RItem.getCollective(item) equip: Option[Ident],
nd <- collective: Ident
if (cid.contains(collective)) RTagItem.deleteItemTags(item) ): F[AddResult] =
else 0.pure[ConnectionIO] store
ni <- .transact(RItem.updateConcEquip(item, collective, equip))
if (tagIds.nonEmpty && cid.contains(collective)) .attempt
RTagItem.insertItemTags(item, tagIds) .map(AddResult.fromUpdate)
else 0.pure[ConnectionIO]
} yield nd + ni
store.transact(db).attempt.map(AddResult.fromUpdate) def addConcEquip(item: Ident, equip: REquipment): F[AddResult] =
} (for {
_ <- OptionT(store.transact(RItem.getCollective(item)))
.filter(_ == equip.cid)
addres <- OptionT.liftF(oequip.add(equip))
_ <- addres match {
case AddResult.Success =>
OptionT.liftF(
store.transact(
RItem.updateConcEquip(item, equip.cid, Some(equip.eid))
)
)
case AddResult.EntityExists(_) =>
OptionT.pure[F](0)
case AddResult.Failure(_) =>
OptionT.pure[F](0)
}
} yield addres)
.getOrElse(AddResult.Failure(new Exception("Collective mismatch")))
def setDirection( def setNotes(
item: Ident, item: Ident,
direction: Direction, notes: Option[String],
collective: Ident collective: Ident
): F[AddResult] = ): F[AddResult] =
store store
.transact(RItem.updateDirection(item, collective, direction)) .transact(RItem.updateNotes(item, collective, notes))
.attempt .attempt
.map(AddResult.fromUpdate) .map(AddResult.fromUpdate)
def setCorrOrg(item: Ident, org: Option[Ident], collective: Ident): F[AddResult] = def setName(item: Ident, name: String, collective: Ident): F[AddResult] =
store store
.transact(RItem.updateCorrOrg(item, collective, org)) .transact(RItem.updateName(item, collective, name))
.attempt .attempt
.map(AddResult.fromUpdate) .map(AddResult.fromUpdate)
def setCorrPerson( def setState(item: Ident, state: ItemState, collective: Ident): F[AddResult] =
item: Ident, store
person: Option[Ident], .transact(RItem.updateStateForCollective(item, state, collective))
collective: Ident .attempt
): F[AddResult] = .map(AddResult.fromUpdate)
store
.transact(RItem.updateCorrPerson(item, collective, person))
.attempt
.map(AddResult.fromUpdate)
def setConcPerson( def setItemDate(
item: Ident, item: Ident,
person: Option[Ident], date: Option[Timestamp],
collective: Ident collective: Ident
): F[AddResult] = ): F[AddResult] =
store store
.transact(RItem.updateConcPerson(item, collective, person)) .transact(RItem.updateDate(item, collective, date))
.attempt .attempt
.map(AddResult.fromUpdate) .map(AddResult.fromUpdate)
def setConcEquip( def setItemDueDate(
item: Ident, item: Ident,
equip: Option[Ident], date: Option[Timestamp],
collective: Ident collective: Ident
): F[AddResult] = ): F[AddResult] =
store store
.transact(RItem.updateConcEquip(item, collective, equip)) .transact(RItem.updateDueDate(item, collective, date))
.attempt .attempt
.map(AddResult.fromUpdate) .map(AddResult.fromUpdate)
def setNotes(item: Ident, notes: Option[String], collective: Ident): F[AddResult] = def deleteItem(itemId: Ident, collective: Ident): F[Int] =
store QItem.delete(store)(itemId, collective)
.transact(RItem.updateNotes(item, collective, notes))
.attempt
.map(AddResult.fromUpdate)
def setName(item: Ident, name: String, collective: Ident): F[AddResult] = def getProposals(item: Ident, collective: Ident): F[MetaProposalList] =
store store.transact(QAttachment.getMetaProposals(item, collective))
.transact(RItem.updateName(item, collective, name))
.attempt
.map(AddResult.fromUpdate)
def setState(item: Ident, state: ItemState, collective: Ident): F[AddResult] = def findAttachmentMeta(id: Ident, collective: Ident): F[Option[RAttachmentMeta]] =
store store.transact(QAttachment.getAttachmentMeta(id, collective))
.transact(RItem.updateStateForCollective(item, state, collective))
.attempt
.map(AddResult.fromUpdate)
def setItemDate( def findByFileCollective(checksum: String, collective: Ident): F[Vector[RItem]] =
item: Ident, store.transact(QItem.findByChecksum(checksum, collective))
date: Option[Timestamp],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateDate(item, collective, date))
.attempt
.map(AddResult.fromUpdate)
def setItemDueDate( def findByFileSource(checksum: String, sourceId: Ident): F[Vector[RItem]] =
item: Ident, store.transact((for {
date: Option[Timestamp], coll <- OptionT(RSource.findCollective(sourceId))
collective: Ident items <- OptionT.liftF(QItem.findByChecksum(checksum, coll))
): F[AddResult] = } yield items).getOrElse(Vector.empty))
store
.transact(RItem.updateDueDate(item, collective, date))
.attempt
.map(AddResult.fromUpdate)
def deleteItem(itemId: Ident, collective: Ident): F[Int] = def deleteAttachment(id: Ident, collective: Ident): F[Int] =
QItem.delete(store)(itemId, collective) QAttachment.deleteSingleAttachment(store)(id, collective)
})
def getProposals(item: Ident, collective: Ident): F[MetaProposalList] = } yield oitem
store.transact(QAttachment.getMetaProposals(item, collective))
def findAttachmentMeta(id: Ident, collective: Ident): F[Option[RAttachmentMeta]] =
store.transact(QAttachment.getAttachmentMeta(id, collective))
def findByFileCollective(checksum: String, collective: Ident): F[Vector[RItem]] =
store.transact(QItem.findByChecksum(checksum, collective))
def findByFileSource(checksum: String, sourceId: Ident): F[Vector[RItem]] =
store.transact((for {
coll <- OptionT(RSource.findCollective(sourceId))
items <- OptionT.liftF(QItem.findByChecksum(checksum, coll))
} yield items).getOrElse(Vector.empty))
def deleteAttachment(id: Ident, collective: Ident): F[Int] =
QAttachment.deleteSingleAttachment(store)(id, collective)
})
} }

View File

@ -1060,7 +1060,7 @@ paths:
schema: schema:
$ref: "#/components/schemas/BasicResult" $ref: "#/components/schemas/BasicResult"
/sec/item/{id}/tags: /sec/item/{id}/tags:
post: put:
tags: [ Item ] tags: [ Item ]
summary: Set new set of tags. summary: Set new set of tags.
description: | description: |
@ -1081,8 +1081,33 @@ paths:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/BasicResult" $ref: "#/components/schemas/BasicResult"
/sec/item/{id}/direction:
post: post:
tags: [ Item ]
summary: Add a new tag to an item.
description: |
Creates a new tag and associates it to the given item.
The tag's `id` and `created` are generated and not used from
the given data, so it can be left empty. Only `name` and
`category` are used, where `category` is optional.
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/id"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Tag"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/direction:
put:
tags: [ Item ] tags: [ Item ]
summary: Set the direction of an item. summary: Set the direction of an item.
description: | description: |
@ -1104,7 +1129,7 @@ paths:
schema: schema:
$ref: "#/components/schemas/BasicResult" $ref: "#/components/schemas/BasicResult"
/sec/item/{id}/corrOrg: /sec/item/{id}/corrOrg:
post: put:
tags: [ Item ] tags: [ Item ]
summary: Set the correspondent organization of an item. summary: Set the correspondent organization of an item.
description: | description: |
@ -1125,8 +1150,30 @@ paths:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/BasicResult" $ref: "#/components/schemas/BasicResult"
/sec/item/{id}/corrPerson:
post: post:
tags: [ Item ]
summary: Set a new correspondent organization of an item.
description: |
Create a new organization and update the correspondent
organization of an item.
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/id"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Organization"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/corrPerson:
put:
tags: [ Item ] tags: [ Item ]
summary: Set the correspondent person of an item. summary: Set the correspondent person of an item.
description: | description: |
@ -1147,8 +1194,30 @@ paths:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/BasicResult" $ref: "#/components/schemas/BasicResult"
/sec/item/{id}/concPerson:
post: post:
tags: [ Item ]
summary: Create and set the correspondent person of an item.
description: |
Creates a new person and updates the correspondent person of
an item.
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/id"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Person"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/concPerson:
put:
tags: [ Item ] tags: [ Item ]
summary: Set the concerning person of an item. summary: Set the concerning person of an item.
description: | description: |
@ -1169,8 +1238,30 @@ paths:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/BasicResult" $ref: "#/components/schemas/BasicResult"
/sec/item/{id}/concEquipment:
post: post:
tags: [ Item ]
summary: Create and set the concerning person of an item.
description: |
Creates a new person and updates the concerning person of an
item.
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/id"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Person"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/concEquipment:
put:
tags: [ Item ] tags: [ Item ]
summary: Set the concering equipment of an item. summary: Set the concering equipment of an item.
description: | description: |
@ -1191,8 +1282,30 @@ paths:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/BasicResult" $ref: "#/components/schemas/BasicResult"
/sec/item/{id}/notes:
post: post:
tags: [ Item ]
summary: Create and set a new the concering equipment of an item.
description: |
Creates a new equipment and sets it as the concering equipment
of an item.
security:
- authTokenHeader: []
parameters:
- $ref: "#/components/parameters/id"
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Equipment"
responses:
200:
description: Ok
content:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/notes:
put:
tags: [ Item ] tags: [ Item ]
summary: Set notes of an item. summary: Set notes of an item.
description: | description: |
@ -1214,7 +1327,7 @@ paths:
schema: schema:
$ref: "#/components/schemas/BasicResult" $ref: "#/components/schemas/BasicResult"
/sec/item/{id}/name: /sec/item/{id}/name:
post: put:
tags: [ Item ] tags: [ Item ]
summary: Set the name of an item. summary: Set the name of an item.
description: | description: |
@ -1272,7 +1385,7 @@ paths:
schema: schema:
$ref: "#/components/schemas/BasicResult" $ref: "#/components/schemas/BasicResult"
/sec/item/{id}/date: /sec/item/{id}/date:
post: put:
tags: [ Item ] tags: [ Item ]
summary: Sets the item date. summary: Sets the item date.
description: | description: |
@ -1294,7 +1407,7 @@ paths:
schema: schema:
$ref: "#/components/schemas/BasicResult" $ref: "#/components/schemas/BasicResult"
/sec/item/{id}/duedate: /sec/item/{id}/duedate:
post: put:
tags: [ Item ] tags: [ Item ]
summary: Sets the items due date. summary: Sets the items due date.
description: | description: |

View File

@ -71,56 +71,96 @@ object ItemRoutes {
resp <- Ok(Conversions.basicResult(res, "Item back to created.")) resp <- Ok(Conversions.basicResult(res, "Item back to created."))
} yield resp } yield resp
case req @ POST -> Root / Ident(id) / "tags" => case req @ PUT -> Root / Ident(id) / "tags" =>
for { for {
tags <- req.as[ReferenceList].map(_.items) tags <- req.as[ReferenceList].map(_.items)
res <- backend.item.setTags(id, tags.map(_.id), user.account.collective) res <- backend.item.setTags(id, tags.map(_.id), user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Tags updated")) resp <- Ok(Conversions.basicResult(res, "Tags updated"))
} yield resp } yield resp
case req @ POST -> Root / Ident(id) / "direction" => case req @ POST -> Root / Ident(id) / "tags" =>
for {
data <- req.as[Tag]
rtag <- Conversions.newTag(data, user.account.collective)
res <- backend.item.addNewTag(id, rtag)
resp <- Ok(Conversions.basicResult(res, "Tag added."))
} yield resp
case req @ PUT -> Root / Ident(id) / "direction" =>
for { for {
dir <- req.as[DirectionValue] dir <- req.as[DirectionValue]
res <- backend.item.setDirection(id, dir.direction, user.account.collective) res <- backend.item.setDirection(id, dir.direction, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Direction updated")) resp <- Ok(Conversions.basicResult(res, "Direction updated"))
} yield resp } yield resp
case req @ POST -> Root / Ident(id) / "corrOrg" => case req @ PUT -> Root / Ident(id) / "corrOrg" =>
for { for {
idref <- req.as[OptionalId] idref <- req.as[OptionalId]
res <- backend.item.setCorrOrg(id, idref.id, user.account.collective) res <- backend.item.setCorrOrg(id, idref.id, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Correspondent organization updated")) resp <- Ok(Conversions.basicResult(res, "Correspondent organization updated"))
} yield resp } yield resp
case req @ POST -> Root / Ident(id) / "corrPerson" => case req @ POST -> Root / Ident(id) / "corrOrg" =>
for {
data <- req.as[Organization]
org <- Conversions.newOrg(data, user.account.collective)
res <- backend.item.addCorrOrg(id, org)
resp <- Ok(Conversions.basicResult(res, "Correspondent organization updated"))
} yield resp
case req @ PUT -> Root / Ident(id) / "corrPerson" =>
for { for {
idref <- req.as[OptionalId] idref <- req.as[OptionalId]
res <- backend.item.setCorrPerson(id, idref.id, user.account.collective) res <- backend.item.setCorrPerson(id, idref.id, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Correspondent person updated")) resp <- Ok(Conversions.basicResult(res, "Correspondent person updated"))
} yield resp } yield resp
case req @ POST -> Root / Ident(id) / "concPerson" => case req @ POST -> Root / Ident(id) / "corrPerson" =>
for {
data <- req.as[Person]
pers <- Conversions.newPerson(data, user.account.collective)
res <- backend.item.addCorrPerson(id, pers)
resp <- Ok(Conversions.basicResult(res, "Correspondent person updated"))
} yield resp
case req @ PUT -> Root / Ident(id) / "concPerson" =>
for { for {
idref <- req.as[OptionalId] idref <- req.as[OptionalId]
res <- backend.item.setConcPerson(id, idref.id, user.account.collective) res <- backend.item.setConcPerson(id, idref.id, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Concerned person updated")) resp <- Ok(Conversions.basicResult(res, "Concerned person updated"))
} yield resp } yield resp
case req @ POST -> Root / Ident(id) / "concEquipment" => case req @ POST -> Root / Ident(id) / "concPerson" =>
for {
data <- req.as[Person]
pers <- Conversions.newPerson(data, user.account.collective)
res <- backend.item.addConcPerson(id, pers)
resp <- Ok(Conversions.basicResult(res, "Concerned person updated"))
} yield resp
case req @ PUT -> Root / Ident(id) / "concEquipment" =>
for { for {
idref <- req.as[OptionalId] idref <- req.as[OptionalId]
res <- backend.item.setConcEquip(id, idref.id, user.account.collective) res <- backend.item.setConcEquip(id, idref.id, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Concerned equipment updated")) resp <- Ok(Conversions.basicResult(res, "Concerned equipment updated"))
} yield resp } yield resp
case req @ POST -> Root / Ident(id) / "notes" => case req @ POST -> Root / Ident(id) / "concEquipment" =>
for {
data <- req.as[Equipment]
equip <- Conversions.newEquipment(data, user.account.collective)
res <- backend.item.addConcEquip(id, equip)
resp <- Ok(Conversions.basicResult(res, "Concerned equipment updated"))
} yield resp
case req @ PUT -> Root / Ident(id) / "notes" =>
for { for {
text <- req.as[OptionalText] text <- req.as[OptionalText]
res <- backend.item.setNotes(id, text.text.notEmpty, user.account.collective) res <- backend.item.setNotes(id, text.text.notEmpty, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Notes updated")) resp <- Ok(Conversions.basicResult(res, "Notes updated"))
} yield resp } yield resp
case req @ POST -> Root / Ident(id) / "name" => case req @ PUT -> Root / Ident(id) / "name" =>
for { for {
text <- req.as[OptionalText] text <- req.as[OptionalText]
res <- backend.item.setName( res <- backend.item.setName(
@ -131,7 +171,7 @@ object ItemRoutes {
resp <- Ok(Conversions.basicResult(res, "Name updated")) resp <- Ok(Conversions.basicResult(res, "Name updated"))
} yield resp } yield resp
case req @ POST -> Root / Ident(id) / "duedate" => case req @ PUT -> Root / Ident(id) / "duedate" =>
for { for {
date <- req.as[OptionalDate] date <- req.as[OptionalDate]
_ <- logger.fdebug(s"Setting item due date to ${date.date}") _ <- logger.fdebug(s"Setting item due date to ${date.date}")
@ -139,7 +179,7 @@ object ItemRoutes {
resp <- Ok(Conversions.basicResult(res, "Item due date updated")) resp <- Ok(Conversions.basicResult(res, "Item due date updated"))
} yield resp } yield resp
case req @ POST -> Root / Ident(id) / "date" => case req @ PUT -> Root / Ident(id) / "date" =>
for { for {
date <- req.as[OptionalDate] date <- req.as[OptionalDate]
_ <- logger.fdebug(s"Setting item date to ${date.date}") _ <- logger.fdebug(s"Setting item date to ${date.date}")

View File

@ -1,5 +1,10 @@
module Api exposing module Api exposing
( cancelJob ( addConcEquip
, addConcPerson
, addCorrOrg
, addCorrPerson
, addTag
, cancelJob
, changePassword , changePassword
, checkCalEvent , checkCalEvent
, createImapSettings , createImapSettings
@ -693,7 +698,7 @@ getContacts flags kind q receive =
-- Tags --- Tags
getTags : Flags -> String -> (Result Http.Error TagList -> msg) -> Cmd msg getTags : Flags -> String -> (Result Http.Error TagList -> msg) -> Cmd msg
@ -732,7 +737,7 @@ deleteTag flags tag receive =
-- Equipments --- Equipments
getEquipments : Flags -> String -> (Result Http.Error EquipmentList -> msg) -> Cmd msg getEquipments : Flags -> String -> (Result Http.Error EquipmentList -> msg) -> Cmd msg
@ -771,7 +776,7 @@ deleteEquip flags equip receive =
-- Organization --- Organization
getOrgLight : Flags -> (Result Http.Error ReferenceList -> msg) -> Cmd msg getOrgLight : Flags -> (Result Http.Error ReferenceList -> msg) -> Cmd msg
@ -819,7 +824,7 @@ deleteOrg flags org receive =
-- Person --- Person
getPersonsLight : Flags -> (Result Http.Error ReferenceList -> msg) -> Cmd msg getPersonsLight : Flags -> (Result Http.Error ReferenceList -> msg) -> Cmd msg
@ -906,7 +911,7 @@ deleteSource flags src receive =
-- Users --- Users
getUsers : Flags -> (Result Http.Error UserList -> msg) -> Cmd msg getUsers : Flags -> (Result Http.Error UserList -> msg) -> Cmd msg
@ -958,7 +963,7 @@ deleteUser flags user receive =
-- Job Queue --- Job Queue
cancelJob : Flags -> String -> (Result Http.Error BasicResult -> msg) -> Cmd msg cancelJob : Flags -> String -> (Result Http.Error BasicResult -> msg) -> Cmd msg
@ -1008,7 +1013,7 @@ getJobQueueStateTask flags =
-- Item --- Item
moveAttachmentBefore : moveAttachmentBefore :
@ -1047,7 +1052,7 @@ itemDetail flags id receive =
setTags : Flags -> String -> ReferenceList -> (Result Http.Error BasicResult -> msg) -> Cmd msg setTags : Flags -> String -> ReferenceList -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setTags flags item tags receive = setTags flags item tags receive =
Http2.authPost Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/tags" { url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/tags"
, account = getAccount flags , account = getAccount flags
, body = Http.jsonBody (Api.Model.ReferenceList.encode tags) , body = Http.jsonBody (Api.Model.ReferenceList.encode tags)
@ -1055,9 +1060,19 @@ setTags flags item tags receive =
} }
addTag : Flags -> String -> Tag -> (Result Http.Error BasicResult -> msg) -> Cmd msg
addTag flags item tag receive =
Http2.authPost
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/tags"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.Tag.encode tag)
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
}
setDirection : Flags -> String -> DirectionValue -> (Result Http.Error BasicResult -> msg) -> Cmd msg setDirection : Flags -> String -> DirectionValue -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setDirection flags item dir receive = setDirection flags item dir receive =
Http2.authPost Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/direction" { url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/direction"
, account = getAccount flags , account = getAccount flags
, body = Http.jsonBody (Api.Model.DirectionValue.encode dir) , body = Http.jsonBody (Api.Model.DirectionValue.encode dir)
@ -1067,7 +1082,7 @@ setDirection flags item dir receive =
setCorrOrg : Flags -> String -> OptionalId -> (Result Http.Error BasicResult -> msg) -> Cmd msg setCorrOrg : Flags -> String -> OptionalId -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setCorrOrg flags item id receive = setCorrOrg flags item id receive =
Http2.authPost Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/corrOrg" { url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/corrOrg"
, account = getAccount flags , account = getAccount flags
, body = Http.jsonBody (Api.Model.OptionalId.encode id) , body = Http.jsonBody (Api.Model.OptionalId.encode id)
@ -1075,9 +1090,19 @@ setCorrOrg flags item id receive =
} }
addCorrOrg : Flags -> String -> Organization -> (Result Http.Error BasicResult -> msg) -> Cmd msg
addCorrOrg flags item org receive =
Http2.authPost
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/corrOrg"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.Organization.encode org)
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
}
setCorrPerson : Flags -> String -> OptionalId -> (Result Http.Error BasicResult -> msg) -> Cmd msg setCorrPerson : Flags -> String -> OptionalId -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setCorrPerson flags item id receive = setCorrPerson flags item id receive =
Http2.authPost Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/corrPerson" { url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/corrPerson"
, account = getAccount flags , account = getAccount flags
, body = Http.jsonBody (Api.Model.OptionalId.encode id) , body = Http.jsonBody (Api.Model.OptionalId.encode id)
@ -1085,9 +1110,19 @@ setCorrPerson flags item id receive =
} }
addCorrPerson : Flags -> String -> Person -> (Result Http.Error BasicResult -> msg) -> Cmd msg
addCorrPerson flags item person receive =
Http2.authPost
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/corrPerson"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.Person.encode person)
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
}
setConcPerson : Flags -> String -> OptionalId -> (Result Http.Error BasicResult -> msg) -> Cmd msg setConcPerson : Flags -> String -> OptionalId -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setConcPerson flags item id receive = setConcPerson flags item id receive =
Http2.authPost Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/concPerson" { url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/concPerson"
, account = getAccount flags , account = getAccount flags
, body = Http.jsonBody (Api.Model.OptionalId.encode id) , body = Http.jsonBody (Api.Model.OptionalId.encode id)
@ -1095,9 +1130,19 @@ setConcPerson flags item id receive =
} }
addConcPerson : Flags -> String -> Person -> (Result Http.Error BasicResult -> msg) -> Cmd msg
addConcPerson flags item person receive =
Http2.authPost
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/concPerson"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.Person.encode person)
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
}
setConcEquip : Flags -> String -> OptionalId -> (Result Http.Error BasicResult -> msg) -> Cmd msg setConcEquip : Flags -> String -> OptionalId -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setConcEquip flags item id receive = setConcEquip flags item id receive =
Http2.authPost Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/concEquipment" { url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/concEquipment"
, account = getAccount flags , account = getAccount flags
, body = Http.jsonBody (Api.Model.OptionalId.encode id) , body = Http.jsonBody (Api.Model.OptionalId.encode id)
@ -1105,9 +1150,19 @@ setConcEquip flags item id receive =
} }
addConcEquip : Flags -> String -> Equipment -> (Result Http.Error BasicResult -> msg) -> Cmd msg
addConcEquip flags item equip receive =
Http2.authPost
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/concEquipment"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.Equipment.encode equip)
, expect = Http.expectJson receive Api.Model.BasicResult.decoder
}
setItemName : Flags -> String -> OptionalText -> (Result Http.Error BasicResult -> msg) -> Cmd msg setItemName : Flags -> String -> OptionalText -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setItemName flags item text receive = setItemName flags item text receive =
Http2.authPost Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/name" { url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/name"
, account = getAccount flags , account = getAccount flags
, body = Http.jsonBody (Api.Model.OptionalText.encode text) , body = Http.jsonBody (Api.Model.OptionalText.encode text)
@ -1117,7 +1172,7 @@ setItemName flags item text receive =
setItemNotes : Flags -> String -> OptionalText -> (Result Http.Error BasicResult -> msg) -> Cmd msg setItemNotes : Flags -> String -> OptionalText -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setItemNotes flags item text receive = setItemNotes flags item text receive =
Http2.authPost Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/notes" { url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/notes"
, account = getAccount flags , account = getAccount flags
, body = Http.jsonBody (Api.Model.OptionalText.encode text) , body = Http.jsonBody (Api.Model.OptionalText.encode text)
@ -1127,7 +1182,7 @@ setItemNotes flags item text receive =
setItemDate : Flags -> String -> OptionalDate -> (Result Http.Error BasicResult -> msg) -> Cmd msg setItemDate : Flags -> String -> OptionalDate -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setItemDate flags item date receive = setItemDate flags item date receive =
Http2.authPost Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/date" { url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/date"
, account = getAccount flags , account = getAccount flags
, body = Http.jsonBody (Api.Model.OptionalDate.encode date) , body = Http.jsonBody (Api.Model.OptionalDate.encode date)
@ -1137,7 +1192,7 @@ setItemDate flags item date receive =
setItemDueDate : Flags -> String -> OptionalDate -> (Result Http.Error BasicResult -> msg) -> Cmd msg setItemDueDate : Flags -> String -> OptionalDate -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setItemDueDate flags item date receive = setItemDueDate flags item date receive =
Http2.authPost Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/duedate" { url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/duedate"
, account = getAccount flags , account = getAccount flags
, body = Http.jsonBody (Api.Model.OptionalDate.encode date) , body = Http.jsonBody (Api.Model.OptionalDate.encode date)
@ -1184,7 +1239,7 @@ getItemProposals flags item receive =
-- Helper --- Helper
getAccount : Flags -> AuthResult getAccount : Flags -> AuthResult

View File

@ -0,0 +1,497 @@
module Comp.DetailEdit exposing
( Model
, Msg
, Value(..)
, initConcPerson
, initCorrPerson
, initEquip
, initOrg
, initTag
, initTagByName
, update
, view
, viewModal
)
{-| Module for allowing to edit metadata in the item-edit menu.
It is only possible to edit one thing at a time, suitable for being
rendered in a modal.
-}
import Api
import Api.Model.BasicResult exposing (BasicResult)
import Api.Model.Equipment exposing (Equipment)
import Api.Model.Organization exposing (Organization)
import Api.Model.Person exposing (Person)
import Api.Model.Tag exposing (Tag)
import Comp.EquipmentForm
import Comp.OrgForm
import Comp.PersonForm
import Comp.TagForm
import Data.Flags exposing (Flags)
import Data.Icons as Icons
import Data.UiSettings exposing (UiSettings)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)
import Http
import Util.Http
type alias Model =
{ form : FormModel
, itemId : String
, submitting : Bool
, result : Maybe BasicResult
}
type FormModel
= TM Comp.TagForm.Model
| PMR Comp.PersonForm.Model
| PMC Comp.PersonForm.Model
| OM Comp.OrgForm.Model
| EM Comp.EquipmentForm.Model
fold :
(Comp.TagForm.Model -> a)
-> (Comp.PersonForm.Model -> a)
-> (Comp.OrgForm.Model -> a)
-> (Comp.EquipmentForm.Model -> a)
-> FormModel
-> a
fold ft fp fo fe model =
case model of
TM tm ->
ft tm
PMR pm ->
fp pm
PMC pm ->
fp pm
OM om ->
fo om
EM em ->
fe em
init : String -> FormModel -> Model
init itemId fm =
{ form = fm
, itemId = itemId
, submitting = False
, result = Nothing
}
initEquip : String -> Comp.EquipmentForm.Model -> Model
initEquip itemId em =
init itemId (EM em)
initOrg : String -> Comp.OrgForm.Model -> Model
initOrg itemId om =
init itemId (OM om)
initCorrPerson : String -> Comp.PersonForm.Model -> Model
initCorrPerson itemId pm =
init itemId (PMR pm)
initConcPerson : String -> Comp.PersonForm.Model -> Model
initConcPerson itemId pm =
init itemId (PMC pm)
initTag : String -> Comp.TagForm.Model -> Model
initTag itemId tm =
init itemId (TM tm)
initTagByName : String -> String -> Model
initTagByName itemId name =
let
tm =
Comp.TagForm.emptyModel
tm_ =
{ tm | name = name }
in
initTag itemId tm_
type Msg
= TagMsg Comp.TagForm.Msg
| PersonMsg Comp.PersonForm.Msg
| OrgMsg Comp.OrgForm.Msg
| EquipMsg Comp.EquipmentForm.Msg
| Submit
| Cancel
| SubmitResp (Result Http.Error BasicResult)
type Value
= SubmitTag Tag
| SubmitPerson Person
| SubmitOrg Organization
| SubmitEquip Equipment
| CancelForm
makeValue : FormModel -> Value
makeValue fm =
case fm of
TM tm ->
SubmitTag (Comp.TagForm.getTag tm)
PMR pm ->
SubmitPerson (Comp.PersonForm.getPerson pm)
PMC pm ->
SubmitPerson (Comp.PersonForm.getPerson pm)
OM om ->
SubmitOrg (Comp.OrgForm.getOrg om)
EM em ->
SubmitEquip (Comp.EquipmentForm.getEquipment em)
--- Update
update : Flags -> Msg -> Model -> ( Model, Cmd Msg, Maybe Value )
update flags msg model =
case msg of
Cancel ->
( model, Cmd.none, Just CancelForm )
SubmitResp (Ok res) ->
( { model
| result = Just res
, submitting = False
}
, Cmd.none
, Just (makeValue model.form)
)
SubmitResp (Err err) ->
( { model
| result = Just (BasicResult False (Util.Http.errorToString err))
, submitting = False
}
, Cmd.none
, Nothing
)
Submit ->
let
failMsg =
Just (BasicResult False "Please fill required fields.")
in
case model.form of
TM tm ->
let
tag =
Comp.TagForm.getTag tm
in
if Comp.TagForm.isValid tm then
( { model | submitting = True }
, Api.addTag flags model.itemId tag SubmitResp
, Nothing
)
else
( { model | result = failMsg }
, Cmd.none
, Nothing
)
OM om ->
let
org =
Comp.OrgForm.getOrg om
in
if Comp.OrgForm.isValid om then
( { model | submitting = True }
, Api.addCorrOrg flags model.itemId org SubmitResp
, Nothing
)
else
( { model | result = failMsg }
, Cmd.none
, Nothing
)
PMC pm ->
let
pers =
Comp.PersonForm.getPerson pm
in
if Comp.PersonForm.isValid pm then
( { model | submitting = True }
, Api.addConcPerson flags model.itemId pers SubmitResp
, Nothing
)
else
( { model | result = failMsg }
, Cmd.none
, Nothing
)
PMR pm ->
let
pers =
Comp.PersonForm.getPerson pm
in
if Comp.PersonForm.isValid pm then
( { model | submitting = True }
, Api.addCorrPerson flags model.itemId pers SubmitResp
, Nothing
)
else
( { model | result = failMsg }
, Cmd.none
, Nothing
)
EM em ->
let
equip =
Comp.EquipmentForm.getEquipment em
in
if Comp.EquipmentForm.isValid em then
( { model | submitting = True }
, Api.addConcEquip flags model.itemId equip SubmitResp
, Nothing
)
else
( { model | result = failMsg }
, Cmd.none
, Nothing
)
TagMsg lm ->
case model.form of
TM tm ->
let
( tm_, tc_ ) =
Comp.TagForm.update flags lm tm
in
( { model
| form = TM tm_
, result = Nothing
}
, Cmd.map TagMsg tc_
, Nothing
)
_ ->
( model, Cmd.none, Nothing )
PersonMsg lm ->
case model.form of
PMR pm ->
let
( pm_, pc_ ) =
Comp.PersonForm.update flags lm pm
in
( { model
| form = PMR pm_
, result = Nothing
}
, Cmd.map PersonMsg pc_
, Nothing
)
PMC pm ->
let
( pm_, pc_ ) =
Comp.PersonForm.update flags lm pm
in
( { model
| form = PMC pm_
, result = Nothing
}
, Cmd.map PersonMsg pc_
, Nothing
)
_ ->
( model, Cmd.none, Nothing )
OrgMsg lm ->
case model.form of
OM om ->
let
( om_, oc_ ) =
Comp.OrgForm.update flags lm om
in
( { model
| form = OM om_
, result = Nothing
}
, Cmd.map OrgMsg oc_
, Nothing
)
_ ->
( model, Cmd.none, Nothing )
EquipMsg lm ->
case model.form of
EM em ->
let
( em_, ec_ ) =
Comp.EquipmentForm.update flags lm em
in
( { model
| form = EM em_
, result = Nothing
}
, Cmd.map EquipMsg ec_
, Nothing
)
_ ->
( model, Cmd.none, Nothing )
--- View
viewButtons : Model -> List (Html Msg)
viewButtons model =
[ button
[ class "ui primary button"
, href "#"
, onClick Submit
, disabled model.submitting
]
[ if model.submitting then
i [ class "ui spinner loading icon" ] []
else
text "Submit"
]
, button
[ class "ui button"
, href "#"
, onClick Cancel
]
[ text "Cancel"
]
]
viewIntern : UiSettings -> Bool -> Model -> List (Html Msg)
viewIntern settings withButtons model =
[ div
[ classList
[ ( "ui message", True )
, ( "error", Maybe.map .success model.result == Just False )
, ( "success", Maybe.map .success model.result == Just True )
, ( "invisible hidden", model.result == Nothing )
]
]
[ Maybe.map .message model.result
|> Maybe.withDefault ""
|> text
]
, case model.form of
TM tm ->
Html.map TagMsg (Comp.TagForm.view tm)
PMR pm ->
Html.map PersonMsg (Comp.PersonForm.view settings pm)
PMC pm ->
Html.map PersonMsg (Comp.PersonForm.view settings pm)
OM om ->
Html.map OrgMsg (Comp.OrgForm.view settings om)
EM em ->
Html.map EquipMsg (Comp.EquipmentForm.view em)
]
++ (if withButtons then
div [ class "ui divider" ] [] :: viewButtons model
else
[]
)
view : UiSettings -> Model -> Html Msg
view settings model =
div []
(viewIntern settings True model)
viewModal : UiSettings -> Maybe Model -> Html Msg
viewModal settings mm =
let
hidden =
mm == Nothing
heading =
fold (\_ -> "Add Tag")
(\_ -> "Add Person")
(\_ -> "Add Organization")
(\_ -> "Add Equipment")
headIcon =
fold (\_ -> Icons.tagIcon "")
(\_ -> Icons.personIcon "")
(\_ -> Icons.organizationIcon "")
(\_ -> Icons.equipmentIcon "")
in
div
[ classList
[ ( "ui inverted modals page dimmer", True )
, ( "invisibe hidden", hidden )
, ( "active", not hidden )
]
, style "display" "flex !important"
]
[ div [ class "ui modal active" ]
[ div [ class "header" ]
[ Maybe.map .form mm
|> Maybe.map headIcon
|> Maybe.withDefault (i [] [])
, Maybe.map .form mm
|> Maybe.map heading
|> Maybe.withDefault ""
|> text
]
, div [ class "scrolling content" ]
(case mm of
Just model ->
viewIntern settings False model
Nothing ->
[]
)
, div [ class "actions" ]
(case mm of
Just model ->
viewButtons model
Nothing ->
[]
)
]
]

View File

@ -88,7 +88,7 @@ makeSingle :
makeSingle opts = makeSingle opts =
makeModel makeModel
{ multiple = False { multiple = False
, searchable = \n -> n > 8 , searchable = \n -> n > 5
, makeOption = opts.makeOption , makeOption = opts.makeOption
, labelColor = \_ -> \_ -> "" , labelColor = \_ -> \_ -> ""
, placeholder = opts.placeholder , placeholder = opts.placeholder
@ -126,7 +126,7 @@ makeMultiple :
makeMultiple opts = makeMultiple opts =
makeModel makeModel
{ multiple = True { multiple = True
, searchable = \n -> n > 8 , searchable = \n -> n > 5
, makeOption = opts.makeOption , makeOption = opts.makeOption
, labelColor = opts.labelColor , labelColor = opts.labelColor
, placeholder = "" , placeholder = ""

View File

@ -240,7 +240,7 @@ viewItem settings item =
[ div [ div
[ class "ui basic grey label" [ class "ui basic grey label"
] ]
[ Icons.dueDateIcon [ Icons.dueDateIcon ""
, text (" " ++ dueDate) , text (" " ++ dueDate)
] ]
] ]

View File

@ -25,10 +25,14 @@ import Api.Model.TagList exposing (TagList)
import Browser.Navigation as Nav import Browser.Navigation as Nav
import Comp.AttachmentMeta import Comp.AttachmentMeta
import Comp.DatePicker import Comp.DatePicker
import Comp.DetailEdit
import Comp.Dropdown exposing (isDropdownChangeMsg) import Comp.Dropdown exposing (isDropdownChangeMsg)
import Comp.Dropzone import Comp.Dropzone
import Comp.EquipmentForm
import Comp.ItemMail import Comp.ItemMail
import Comp.MarkdownInput import Comp.MarkdownInput
import Comp.OrgForm
import Comp.PersonForm
import Comp.SentMails import Comp.SentMails
import Comp.YesNoDimmer import Comp.YesNoDimmer
import Data.Direction exposing (Direction) import Data.Direction exposing (Direction)
@ -93,6 +97,7 @@ type alias Model =
, errored : Set String , errored : Set String
, loading : Set String , loading : Set String
, attachDD : DD.Model String String , attachDD : DD.Model String String
, modalEdit : Maybe Comp.DetailEdit.Model
} }
@ -179,6 +184,7 @@ emptyModel =
, errored = Set.empty , errored = Set.empty
, loading = Set.empty , loading = Set.empty
, attachDD = DD.init , attachDD = DD.init
, modalEdit = Nothing
} }
@ -242,10 +248,17 @@ type Msg
| AddFilesProgress String Http.Progress | AddFilesProgress String Http.Progress
| AddFilesReset | AddFilesReset
| AttachDDMsg (DD.Msg String String) | AttachDDMsg (DD.Msg String String)
| ModalEditMsg Comp.DetailEdit.Msg
| StartTagModal
| StartCorrOrgModal
| StartCorrPersonModal
| StartConcPersonModal
| StartEquipModal
| CloseModal
-- update --- Update
getOptions : Flags -> Cmd Msg getOptions : Flags -> Cmd Msg
@ -511,6 +524,7 @@ update key flags next msg model =
, itemDate = item.itemDate , itemDate = item.itemDate
, dueDate = item.dueDate , dueDate = item.dueDate
, visibleAttach = 0 , visibleAttach = 0
, modalEdit = Nothing
} }
, Cmd.batch , Cmd.batch
[ c1 [ c1
@ -1202,9 +1216,95 @@ update key flags next msg model =
in in
noSub ( { model | attachDD = model_ }, cmd ) noSub ( { model | attachDD = model_ }, cmd )
ModalEditMsg lm ->
case model.modalEdit of
Just mm ->
let
( mm_, mc_, mv ) =
Comp.DetailEdit.update flags lm mm
( model_, cmd_ ) =
case mv of
Just Comp.DetailEdit.CancelForm ->
( { model | modalEdit = Nothing }, Cmd.none )
Just _ ->
( model, Api.itemDetail flags model.item.id GetItemResp )
Nothing ->
( { model | modalEdit = Just mm_ }, Cmd.none )
in
noSub ( model_, Cmd.batch [ cmd_, Cmd.map ModalEditMsg mc_ ] )
Nothing ->
noSub ( model, Cmd.none )
StartTagModal ->
noSub
( { model
| modalEdit = Just (Comp.DetailEdit.initTagByName model.item.id "")
}
, Cmd.none
)
StartCorrOrgModal ->
noSub
( { model
| modalEdit =
Just
(Comp.DetailEdit.initOrg
model.item.id
Comp.OrgForm.emptyModel
)
}
, Cmd.none
)
StartCorrPersonModal ->
noSub
( { model
| modalEdit =
Just
(Comp.DetailEdit.initCorrPerson
model.item.id
Comp.PersonForm.emptyModel
)
}
, Cmd.none
)
StartConcPersonModal ->
noSub
( { model
| modalEdit =
Just
(Comp.DetailEdit.initConcPerson
model.item.id
Comp.PersonForm.emptyModel
)
}
, Cmd.none
)
StartEquipModal ->
noSub
( { model
| modalEdit =
Just
(Comp.DetailEdit.initEquip
model.item.id
Comp.EquipmentForm.emptyModel
)
}
, Cmd.none
)
CloseModal ->
noSub ( { model | modalEdit = Nothing }, Cmd.none )
-- view
--- View
actionInputDatePicker : DatePicker.Settings actionInputDatePicker : DatePicker.Settings
@ -1219,7 +1319,8 @@ actionInputDatePicker =
view : { prev : Maybe String, next : Maybe String } -> UiSettings -> Model -> Html Msg view : { prev : Maybe String, next : Maybe String } -> UiSettings -> Model -> Html Msg
view inav settings model = view inav settings model =
div [] div []
[ renderItemInfo settings model [ Html.map ModalEditMsg (Comp.DetailEdit.viewModal settings model.modalEdit)
, renderItemInfo settings model
, div , div
[ classList [ classList
[ ( "ui ablue-comp menu", True ) [ ( "ui ablue-comp menu", True )
@ -1674,7 +1775,7 @@ renderItemInfo settings model =
[ class "item" [ class "item"
, title "Due Date" , title "Due Date"
] ]
[ Icons.dueDateIcon [ Icons.dueDateIcon "grey"
, Maybe.map Util.Time.formatDate model.item.dueDate , Maybe.map Util.Time.formatDate model.item.dueDate
|> Maybe.withDefault "" |> Maybe.withDefault ""
|> text |> text
@ -1816,12 +1917,24 @@ renderEditButtons model =
renderEditForm : UiSettings -> Model -> Html Msg renderEditForm : UiSettings -> Model -> Html Msg
renderEditForm settings model = renderEditForm settings model =
let
addIconLink tip m =
a
[ class "right-float"
, href "#"
, title tip
, onClick m
]
[ i [ class "grey plus link icon" ] []
]
in
div [ class "ui attached segment" ] div [ class "ui attached segment" ]
[ div [ class "ui form" ] [ div [ class "ui form" ]
[ div [ class "field" ] [ div [ class "field" ]
[ label [] [ label []
[ i [ class "tags icon" ] [] [ Icons.tagsIcon "grey"
, text "Tags" , text "Tags"
, addIconLink "Add new tag" StartTagModal
] ]
, Html.map TagDropdownMsg (Comp.Dropdown.view settings model.tagModel) , Html.map TagDropdownMsg (Comp.Dropdown.view settings model.tagModel)
] ]
@ -1838,11 +1951,17 @@ renderEditForm settings model =
] ]
] ]
, div [ class "field" ] , div [ class "field" ]
[ label [] [ text "Direction" ] [ label []
[ Icons.directionIcon "grey"
, text "Direction"
]
, Html.map DirDropdownMsg (Comp.Dropdown.view settings model.directionModel) , Html.map DirDropdownMsg (Comp.Dropdown.view settings model.directionModel)
] ]
, div [ class " field" ] , div [ class " field" ]
[ label [] [ text "Date" ] [ label []
[ Icons.dateIcon "grey"
, text "Date"
]
, div [ class "ui action input" ] , div [ class "ui action input" ]
[ Html.map ItemDatePickerMsg [ Html.map ItemDatePickerMsg
(Comp.DatePicker.viewTime (Comp.DatePicker.viewTime
@ -1857,7 +1976,10 @@ renderEditForm settings model =
, renderItemDateSuggestions model , renderItemDateSuggestions model
] ]
, div [ class " field" ] , div [ class " field" ]
[ label [] [ text "Due Date" ] [ label []
[ Icons.dueDateIcon "grey"
, text "Due Date"
]
, div [ class "ui action input" ] , div [ class "ui action input" ]
[ Html.map DueDatePickerMsg [ Html.map DueDatePickerMsg
(Comp.DatePicker.viewTime (Comp.DatePicker.viewTime
@ -1871,30 +1993,46 @@ renderEditForm settings model =
, renderDueDateSuggestions model , renderDueDateSuggestions model
] ]
, h4 [ class "ui dividing header" ] , h4 [ class "ui dividing header" ]
[ i [ class "tiny envelope outline icon" ] [] [ Icons.correspondentIcon
, text "Correspondent" , text "Correspondent"
] ]
, div [ class "field" ] , div [ class "field" ]
[ label [] [ text "Organization" ] [ label []
[ Icons.organizationIcon "grey"
, text "Organization"
, addIconLink "Add new organization" StartCorrOrgModal
]
, Html.map OrgDropdownMsg (Comp.Dropdown.view settings model.corrOrgModel) , Html.map OrgDropdownMsg (Comp.Dropdown.view settings model.corrOrgModel)
, renderOrgSuggestions model , renderOrgSuggestions model
] ]
, div [ class "field" ] , div [ class "field" ]
[ label [] [ text "Person" ] [ label []
[ Icons.personIcon "grey"
, text "Person"
, addIconLink "Add new correspondent person" StartCorrPersonModal
]
, Html.map CorrPersonMsg (Comp.Dropdown.view settings model.corrPersonModel) , Html.map CorrPersonMsg (Comp.Dropdown.view settings model.corrPersonModel)
, renderCorrPersonSuggestions model , renderCorrPersonSuggestions model
] ]
, h4 [ class "ui dividing header" ] , h4 [ class "ui dividing header" ]
[ i [ class "tiny comment outline icon" ] [] [ Icons.concernedIcon
, text "Concerning" , text "Concerning"
] ]
, div [ class "field" ] , div [ class "field" ]
[ label [] [ text "Person" ] [ label []
[ Icons.personIcon "grey"
, text "Person"
, addIconLink "Add new concerning person" StartConcPersonModal
]
, Html.map ConcPersonMsg (Comp.Dropdown.view settings model.concPersonModel) , Html.map ConcPersonMsg (Comp.Dropdown.view settings model.concPersonModel)
, renderConcPersonSuggestions model , renderConcPersonSuggestions model
] ]
, div [ class "field" ] , div [ class "field" ]
[ label [] [ text "Equipment" ] [ label []
[ Icons.equipmentIcon "grey"
, text "Equipment"
, addIconLink "Add new equipment" StartEquipModal
]
, Html.map ConcEquipMsg (Comp.Dropdown.view settings model.concEquipModel) , Html.map ConcEquipMsg (Comp.Dropdown.view settings model.concEquipModel)
, renderConcEquipSuggestions model , renderConcEquipSuggestions model
] ]

View File

@ -5,10 +5,24 @@ module Data.Icons exposing
, concernedIcon , concernedIcon
, correspondent , correspondent
, correspondentIcon , correspondentIcon
, date
, dateIcon
, direction
, directionIcon
, dueDate , dueDate
, dueDateIcon , dueDateIcon
, editNotes , editNotes
, editNotesIcon , editNotesIcon
, equipment
, equipmentIcon
, organization
, organizationIcon
, person
, personIcon
, tag
, tagIcon
, tags
, tagsIcon
) )
import Html exposing (Html, i) import Html exposing (Html, i)
@ -35,14 +49,24 @@ correspondentIcon =
i [ class correspondent ] [] i [ class correspondent ] []
date : String
date =
"calendar outline icon"
dateIcon : String -> Html msg
dateIcon classes =
i [ class (date ++ " " ++ classes) ] []
dueDate : String dueDate : String
dueDate = dueDate =
"bell icon" "bell icon"
dueDateIcon : Html msg dueDateIcon : String -> Html msg
dueDateIcon = dueDateIcon classes =
i [ class dueDate ] [] i [ class (dueDate ++ " " ++ classes) ] []
editNotes : String editNotes : String
@ -63,3 +87,63 @@ addFiles =
addFilesIcon : Html msg addFilesIcon : Html msg
addFilesIcon = addFilesIcon =
i [ class addFiles ] [] i [ class addFiles ] []
tag : String
tag =
"tag icon"
tagIcon : String -> Html msg
tagIcon classes =
i [ class (tag ++ " " ++ classes) ] []
tags : String
tags =
"tags icon"
tagsIcon : String -> Html msg
tagsIcon classes =
i [ class (tags ++ " " ++ classes) ] []
direction : String
direction =
"exchange icon"
directionIcon : String -> Html msg
directionIcon classes =
i [ class (direction ++ " " ++ classes) ] []
person : String
person =
"user icon"
personIcon : String -> Html msg
personIcon classes =
i [ class (person ++ " " ++ classes) ] []
organization : String
organization =
"factory icon"
organizationIcon : String -> Html msg
organizationIcon classes =
i [ class (organization ++ " " ++ classes) ] []
equipment : String
equipment =
"box icon"
equipmentIcon : String -> Html msg
equipmentIcon classes =
i [ class (equipment ++ " " ++ classes) ] []

View File

@ -4,6 +4,7 @@ import Comp.EquipmentManage
import Comp.OrgManage import Comp.OrgManage
import Comp.PersonManage import Comp.PersonManage
import Comp.TagManage import Comp.TagManage
import Data.Icons as Icons
import Data.UiSettings exposing (UiSettings) import Data.UiSettings exposing (UiSettings)
import Html exposing (..) import Html exposing (..)
import Html.Attributes exposing (..) import Html.Attributes exposing (..)
@ -25,28 +26,28 @@ view settings model =
[ classActive (model.currentTab == Just TagTab) "link icon item" [ classActive (model.currentTab == Just TagTab) "link icon item"
, onClick (SetTab TagTab) , onClick (SetTab TagTab)
] ]
[ i [ class "tag icon" ] [] [ Icons.tagIcon ""
, text "Tag" , text "Tag"
] ]
, div , div
[ classActive (model.currentTab == Just EquipTab) "link icon item" [ classActive (model.currentTab == Just EquipTab) "link icon item"
, onClick (SetTab EquipTab) , onClick (SetTab EquipTab)
] ]
[ i [ class "box icon" ] [] [ Icons.equipmentIcon ""
, text "Equipment" , text "Equipment"
] ]
, div , div
[ classActive (model.currentTab == Just OrgTab) "link icon item" [ classActive (model.currentTab == Just OrgTab) "link icon item"
, onClick (SetTab OrgTab) , onClick (SetTab OrgTab)
] ]
[ i [ class "factory icon" ] [] [ Icons.organizationIcon ""
, text "Organization" , text "Organization"
] ]
, div , div
[ classActive (model.currentTab == Just PersonTab) "link icon item" [ classActive (model.currentTab == Just PersonTab) "link icon item"
, onClick (SetTab PersonTab) , onClick (SetTab PersonTab)
] ]
[ i [ class "user icon" ] [] [ Icons.personIcon ""
, text "Person" , text "Person"
] ]
] ]
@ -77,7 +78,7 @@ view settings model =
viewTags : Model -> List (Html Msg) viewTags : Model -> List (Html Msg)
viewTags model = viewTags model =
[ h2 [ class "ui header" ] [ h2 [ class "ui header" ]
[ i [ class "ui tag icon" ] [] [ Icons.tagIcon ""
, div [ class "content" ] , div [ class "content" ]
[ text "Tags" [ text "Tags"
] ]
@ -89,7 +90,7 @@ viewTags model =
viewEquip : Model -> List (Html Msg) viewEquip : Model -> List (Html Msg)
viewEquip model = viewEquip model =
[ h2 [ class "ui header" ] [ h2 [ class "ui header" ]
[ i [ class "ui box icon" ] [] [ Icons.equipmentIcon ""
, div [ class "content" ] , div [ class "content" ]
[ text "Equipment" [ text "Equipment"
] ]
@ -101,7 +102,7 @@ viewEquip model =
viewOrg : UiSettings -> Model -> List (Html Msg) viewOrg : UiSettings -> Model -> List (Html Msg)
viewOrg settings model = viewOrg settings model =
[ h2 [ class "ui header" ] [ h2 [ class "ui header" ]
[ i [ class "ui factory icon" ] [] [ Icons.organizationIcon ""
, div [ class "content" ] , div [ class "content" ]
[ text "Organizations" [ text "Organizations"
] ]
@ -113,7 +114,7 @@ viewOrg settings model =
viewPerson : UiSettings -> Model -> List (Html Msg) viewPerson : UiSettings -> Model -> List (Html Msg)
viewPerson settings model = viewPerson settings model =
[ h2 [ class "ui header" ] [ h2 [ class "ui header" ]
[ i [ class "ui user icon" ] [] [ Icons.personIcon ""
, div [ class "content" ] , div [ class "content" ]
[ text "Person" [ text "Person"
] ]

View File

@ -9,7 +9,7 @@ makeDropdownModel : Comp.Dropdown.Model Tag
makeDropdownModel = makeDropdownModel =
Comp.Dropdown.makeModel Comp.Dropdown.makeModel
{ multiple = True { multiple = True
, searchable = \n -> n > 4 , searchable = \n -> n > 5
, makeOption = \tag -> { value = tag.id, text = tag.name } , makeOption = \tag -> { value = tag.id, text = tag.name }
, labelColor = , labelColor =
\tag -> \tag ->