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
commit 6e42ef9d28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1311 additions and 257 deletions

View File

@ -43,18 +43,30 @@ trait OItem[F[_]] {
collective: Ident
): F[Option[AttachmentArchiveData[F]]]
/** Sets the given tags (removing all existing ones). */
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 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 addCorrPerson(item: Ident, person: OOrganization.PersonAndContacts): 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 addConcEquip(item: Ident, equip: REquipment): F[AddResult]
def setNotes(item: Ident, notes: Option[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]] =
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(
itemId: Ident,
source: Ident,
target: Ident
): F[AddResult] =
store
.transact(QItem.moveAttachmentBefore(itemId, source, target))
.attempt
.map(AddResult.fromUpdate)
def findItem(id: Ident, collective: Ident): F[Option[ItemData]] =
store
.transact(QItem.findItem(id))
.map(opt => opt.flatMap(_.filterCollective(collective)))
def findItem(id: Ident, collective: Ident): F[Option[ItemData]] =
store
.transact(QItem.findItem(id))
.map(opt => opt.flatMap(_.filterCollective(collective)))
def findItems(q: Query, batch: Batch): F[Vector[ListItem]] =
store
.transact(QItem.findItems(q, batch).take(batch.limit.toLong))
.compile
.toVector
def findItems(q: Query, batch: Batch): F[Vector[ListItem]] =
store
.transact(QItem.findItems(q, batch).take(batch.limit.toLong))
.compile
.toVector
def findItemsWithTags(q: Query, batch: Batch): F[Vector[ListItemWithTags]] =
store
.transact(QItem.findItemsWithTags(q, batch).take(batch.limit.toLong))
.compile
.toVector
def findItemsWithTags(q: Query, batch: Batch): F[Vector[ListItemWithTags]] =
store
.transact(QItem.findItemsWithTags(q, batch).take(batch.limit.toLong))
.compile
.toVector
def findAttachment(id: Ident, collective: Ident): F[Option[AttachmentData[F]]] =
store
.transact(RAttachment.findByIdAndCollective(id, collective))
.flatMap({
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]]] =
store
.transact(RAttachment.findByIdAndCollective(id, collective))
.flatMap({
case Some(ra) =>
makeBinaryData(ra.fileId) { m =>
AttachmentData[F](
ra,
m,
store.bitpeace.fetchData2(RangeDef.all)(Stream.emit(m))
case None =>
(None: Option[AttachmentData[F]]).pure[F]
})
def findAttachmentSource(
id: Ident,
collective: Ident
): F[Option[AttachmentSourceData[F]]] =
store
.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 =>
(None: Option[AttachmentData[F]]).pure[F]
})
def setDirection(
item: Ident,
direction: Direction,
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateDirection(item, collective, direction))
.attempt
.map(AddResult.fromUpdate)
def findAttachmentSource(
id: Ident,
collective: Ident
): F[Option[AttachmentSourceData[F]]] =
store
.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))
def setCorrOrg(item: Ident, org: Option[Ident], collective: Ident): F[AddResult] =
store
.transact(RItem.updateCorrOrg(item, collective, org))
.attempt
.map(AddResult.fromUpdate)
def addCorrOrg(item: Ident, org: OOrganization.OrgAndContacts): F[AddResult] =
(for {
_ <- OptionT(store.transact(RItem.getCollective(item)))
.filter(_ == org.org.cid)
addres <- OptionT.liftF(oorg.addOrg(org))
_ <- addres match {
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 =>
(None: Option[AttachmentSourceData[F]]).pure[F]
})
def setCorrPerson(
item: Ident,
person: Option[Ident],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateCorrPerson(item, collective, person))
.attempt
.map(AddResult.fromUpdate)
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))
def addCorrPerson(
item: Ident,
person: OOrganization.PersonAndContacts
): F[AddResult] =
(for {
_ <- OptionT(store.transact(RItem.getCollective(item)))
.filter(_ == person.person.cid)
addres <- OptionT.liftF(oorg.addPerson(person))
_ <- addres match {
case AddResult.Success =>
OptionT.liftF(
store.transact(
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 =>
(None: Option[AttachmentArchiveData[F]]).pure[F]
})
def setConcPerson(
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]] =
store.bitpeace
.get(fileId.id)
.unNoneTerminate
.compile
.last
.map(
_.map(m => f(m))
)
def addConcPerson(
item: Ident,
person: OOrganization.PersonAndContacts
): F[AddResult] =
(for {
_ <- OptionT(store.transact(RItem.getCollective(item)))
.filter(_ == person.person.cid)
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] = {
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
def setConcEquip(
item: Ident,
equip: Option[Ident],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateConcEquip(item, collective, equip))
.attempt
.map(AddResult.fromUpdate)
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(
item: Ident,
direction: Direction,
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateDirection(item, collective, direction))
.attempt
.map(AddResult.fromUpdate)
def setNotes(
item: Ident,
notes: Option[String],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateNotes(item, collective, notes))
.attempt
.map(AddResult.fromUpdate)
def setCorrOrg(item: Ident, org: Option[Ident], collective: Ident): F[AddResult] =
store
.transact(RItem.updateCorrOrg(item, collective, org))
.attempt
.map(AddResult.fromUpdate)
def setName(item: Ident, name: String, collective: Ident): F[AddResult] =
store
.transact(RItem.updateName(item, collective, name))
.attempt
.map(AddResult.fromUpdate)
def setCorrPerson(
item: Ident,
person: Option[Ident],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateCorrPerson(item, collective, person))
.attempt
.map(AddResult.fromUpdate)
def setState(item: Ident, state: ItemState, collective: Ident): F[AddResult] =
store
.transact(RItem.updateStateForCollective(item, state, collective))
.attempt
.map(AddResult.fromUpdate)
def setConcPerson(
item: Ident,
person: Option[Ident],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateConcPerson(item, collective, person))
.attempt
.map(AddResult.fromUpdate)
def setItemDate(
item: Ident,
date: Option[Timestamp],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateDate(item, collective, date))
.attempt
.map(AddResult.fromUpdate)
def setConcEquip(
item: Ident,
equip: Option[Ident],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateConcEquip(item, collective, equip))
.attempt
.map(AddResult.fromUpdate)
def setItemDueDate(
item: Ident,
date: Option[Timestamp],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateDueDate(item, collective, date))
.attempt
.map(AddResult.fromUpdate)
def setNotes(item: Ident, notes: Option[String], collective: Ident): F[AddResult] =
store
.transact(RItem.updateNotes(item, collective, notes))
.attempt
.map(AddResult.fromUpdate)
def deleteItem(itemId: Ident, collective: Ident): F[Int] =
QItem.delete(store)(itemId, collective)
def setName(item: Ident, name: String, collective: Ident): F[AddResult] =
store
.transact(RItem.updateName(item, collective, name))
.attempt
.map(AddResult.fromUpdate)
def getProposals(item: Ident, collective: Ident): F[MetaProposalList] =
store.transact(QAttachment.getMetaProposals(item, collective))
def setState(item: Ident, state: ItemState, collective: Ident): F[AddResult] =
store
.transact(RItem.updateStateForCollective(item, state, collective))
.attempt
.map(AddResult.fromUpdate)
def findAttachmentMeta(id: Ident, collective: Ident): F[Option[RAttachmentMeta]] =
store.transact(QAttachment.getAttachmentMeta(id, collective))
def setItemDate(
item: Ident,
date: Option[Timestamp],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateDate(item, collective, date))
.attempt
.map(AddResult.fromUpdate)
def findByFileCollective(checksum: String, collective: Ident): F[Vector[RItem]] =
store.transact(QItem.findByChecksum(checksum, collective))
def setItemDueDate(
item: Ident,
date: Option[Timestamp],
collective: Ident
): F[AddResult] =
store
.transact(RItem.updateDueDate(item, collective, date))
.attempt
.map(AddResult.fromUpdate)
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 deleteItem(itemId: Ident, collective: Ident): F[Int] =
QItem.delete(store)(itemId, collective)
def getProposals(item: Ident, collective: Ident): F[MetaProposalList] =
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)
})
def deleteAttachment(id: Ident, collective: Ident): F[Int] =
QAttachment.deleteSingleAttachment(store)(id, collective)
})
} yield oitem
}

View File

@ -1060,7 +1060,7 @@ paths:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/tags:
post:
put:
tags: [ Item ]
summary: Set new set of tags.
description: |
@ -1081,8 +1081,33 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/direction:
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 ]
summary: Set the direction of an item.
description: |
@ -1104,7 +1129,7 @@ paths:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/corrOrg:
post:
put:
tags: [ Item ]
summary: Set the correspondent organization of an item.
description: |
@ -1125,8 +1150,30 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/corrPerson:
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 ]
summary: Set the correspondent person of an item.
description: |
@ -1147,8 +1194,30 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/concPerson:
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 ]
summary: Set the concerning person of an item.
description: |
@ -1169,8 +1238,30 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/concEquipment:
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 ]
summary: Set the concering equipment of an item.
description: |
@ -1191,8 +1282,30 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/notes:
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 ]
summary: Set notes of an item.
description: |
@ -1214,7 +1327,7 @@ paths:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/name:
post:
put:
tags: [ Item ]
summary: Set the name of an item.
description: |
@ -1272,7 +1385,7 @@ paths:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/date:
post:
put:
tags: [ Item ]
summary: Sets the item date.
description: |
@ -1294,7 +1407,7 @@ paths:
schema:
$ref: "#/components/schemas/BasicResult"
/sec/item/{id}/duedate:
post:
put:
tags: [ Item ]
summary: Sets the items due date.
description: |

View File

@ -71,56 +71,96 @@ object ItemRoutes {
resp <- Ok(Conversions.basicResult(res, "Item back to created."))
} yield resp
case req @ POST -> Root / Ident(id) / "tags" =>
case req @ PUT -> Root / Ident(id) / "tags" =>
for {
tags <- req.as[ReferenceList].map(_.items)
res <- backend.item.setTags(id, tags.map(_.id), user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Tags updated"))
} 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 {
dir <- req.as[DirectionValue]
res <- backend.item.setDirection(id, dir.direction, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Direction updated"))
} yield resp
case req @ POST -> Root / Ident(id) / "corrOrg" =>
case req @ PUT -> Root / Ident(id) / "corrOrg" =>
for {
idref <- req.as[OptionalId]
res <- backend.item.setCorrOrg(id, idref.id, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Correspondent organization updated"))
} 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 {
idref <- req.as[OptionalId]
res <- backend.item.setCorrPerson(id, idref.id, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Correspondent person updated"))
} 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 {
idref <- req.as[OptionalId]
res <- backend.item.setConcPerson(id, idref.id, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Concerned person updated"))
} 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 {
idref <- req.as[OptionalId]
res <- backend.item.setConcEquip(id, idref.id, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Concerned equipment updated"))
} 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 {
text <- req.as[OptionalText]
res <- backend.item.setNotes(id, text.text.notEmpty, user.account.collective)
resp <- Ok(Conversions.basicResult(res, "Notes updated"))
} yield resp
case req @ POST -> Root / Ident(id) / "name" =>
case req @ PUT -> Root / Ident(id) / "name" =>
for {
text <- req.as[OptionalText]
res <- backend.item.setName(
@ -131,7 +171,7 @@ object ItemRoutes {
resp <- Ok(Conversions.basicResult(res, "Name updated"))
} yield resp
case req @ POST -> Root / Ident(id) / "duedate" =>
case req @ PUT -> Root / Ident(id) / "duedate" =>
for {
date <- req.as[OptionalDate]
_ <- 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"))
} yield resp
case req @ POST -> Root / Ident(id) / "date" =>
case req @ PUT -> Root / Ident(id) / "date" =>
for {
date <- req.as[OptionalDate]
_ <- logger.fdebug(s"Setting item date to ${date.date}")

View File

@ -1,5 +1,10 @@
module Api exposing
( cancelJob
( addConcEquip
, addConcPerson
, addCorrOrg
, addCorrPerson
, addTag
, cancelJob
, changePassword
, checkCalEvent
, createImapSettings
@ -693,7 +698,7 @@ getContacts flags kind q receive =
-- Tags
--- Tags
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
@ -771,7 +776,7 @@ deleteEquip flags equip receive =
-- Organization
--- Organization
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
@ -906,7 +911,7 @@ deleteSource flags src receive =
-- Users
--- Users
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
@ -1008,7 +1013,7 @@ getJobQueueStateTask flags =
-- Item
--- Item
moveAttachmentBefore :
@ -1047,7 +1052,7 @@ itemDetail flags id receive =
setTags : Flags -> String -> ReferenceList -> (Result Http.Error BasicResult -> msg) -> Cmd msg
setTags flags item tags receive =
Http2.authPost
Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/tags"
, account = getAccount flags
, 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 item dir receive =
Http2.authPost
Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/direction"
, account = getAccount flags
, 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 item id receive =
Http2.authPost
Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/corrOrg"
, account = getAccount flags
, 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 item id receive =
Http2.authPost
Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/corrPerson"
, account = getAccount flags
, 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 item id receive =
Http2.authPost
Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/concPerson"
, account = getAccount flags
, 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 item id receive =
Http2.authPost
Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/concEquipment"
, account = getAccount flags
, 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 item text receive =
Http2.authPost
Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/name"
, account = getAccount flags
, 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 item text receive =
Http2.authPost
Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/notes"
, account = getAccount flags
, 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 item date receive =
Http2.authPost
Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/date"
, account = getAccount flags
, 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 item date receive =
Http2.authPost
Http2.authPut
{ url = flags.config.baseUrl ++ "/api/v1/sec/item/" ++ item ++ "/duedate"
, account = getAccount flags
, body = Http.jsonBody (Api.Model.OptionalDate.encode date)
@ -1184,7 +1239,7 @@ getItemProposals flags item receive =
-- Helper
--- Helper
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 =
makeModel
{ multiple = False
, searchable = \n -> n > 8
, searchable = \n -> n > 5
, makeOption = opts.makeOption
, labelColor = \_ -> \_ -> ""
, placeholder = opts.placeholder
@ -126,7 +126,7 @@ makeMultiple :
makeMultiple opts =
makeModel
{ multiple = True
, searchable = \n -> n > 8
, searchable = \n -> n > 5
, makeOption = opts.makeOption
, labelColor = opts.labelColor
, placeholder = ""

View File

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

View File

@ -25,10 +25,14 @@ import Api.Model.TagList exposing (TagList)
import Browser.Navigation as Nav
import Comp.AttachmentMeta
import Comp.DatePicker
import Comp.DetailEdit
import Comp.Dropdown exposing (isDropdownChangeMsg)
import Comp.Dropzone
import Comp.EquipmentForm
import Comp.ItemMail
import Comp.MarkdownInput
import Comp.OrgForm
import Comp.PersonForm
import Comp.SentMails
import Comp.YesNoDimmer
import Data.Direction exposing (Direction)
@ -93,6 +97,7 @@ type alias Model =
, errored : Set String
, loading : Set String
, attachDD : DD.Model String String
, modalEdit : Maybe Comp.DetailEdit.Model
}
@ -179,6 +184,7 @@ emptyModel =
, errored = Set.empty
, loading = Set.empty
, attachDD = DD.init
, modalEdit = Nothing
}
@ -242,10 +248,17 @@ type Msg
| AddFilesProgress String Http.Progress
| AddFilesReset
| AttachDDMsg (DD.Msg String String)
| ModalEditMsg Comp.DetailEdit.Msg
| StartTagModal
| StartCorrOrgModal
| StartCorrPersonModal
| StartConcPersonModal
| StartEquipModal
| CloseModal
-- update
--- Update
getOptions : Flags -> Cmd Msg
@ -511,6 +524,7 @@ update key flags next msg model =
, itemDate = item.itemDate
, dueDate = item.dueDate
, visibleAttach = 0
, modalEdit = Nothing
}
, Cmd.batch
[ c1
@ -1202,9 +1216,95 @@ update key flags next msg model =
in
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
@ -1219,7 +1319,8 @@ actionInputDatePicker =
view : { prev : Maybe String, next : Maybe String } -> UiSettings -> Model -> Html Msg
view inav settings model =
div []
[ renderItemInfo settings model
[ Html.map ModalEditMsg (Comp.DetailEdit.viewModal settings model.modalEdit)
, renderItemInfo settings model
, div
[ classList
[ ( "ui ablue-comp menu", True )
@ -1674,7 +1775,7 @@ renderItemInfo settings model =
[ class "item"
, title "Due Date"
]
[ Icons.dueDateIcon
[ Icons.dueDateIcon "grey"
, Maybe.map Util.Time.formatDate model.item.dueDate
|> Maybe.withDefault ""
|> text
@ -1816,12 +1917,24 @@ renderEditButtons model =
renderEditForm : UiSettings -> Model -> Html Msg
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 form" ]
[ div [ class "field" ]
[ label []
[ i [ class "tags icon" ] []
[ Icons.tagsIcon "grey"
, text "Tags"
, addIconLink "Add new tag" StartTagModal
]
, Html.map TagDropdownMsg (Comp.Dropdown.view settings model.tagModel)
]
@ -1838,11 +1951,17 @@ renderEditForm settings model =
]
]
, div [ class "field" ]
[ label [] [ text "Direction" ]
[ label []
[ Icons.directionIcon "grey"
, text "Direction"
]
, Html.map DirDropdownMsg (Comp.Dropdown.view settings model.directionModel)
]
, div [ class " field" ]
[ label [] [ text "Date" ]
[ label []
[ Icons.dateIcon "grey"
, text "Date"
]
, div [ class "ui action input" ]
[ Html.map ItemDatePickerMsg
(Comp.DatePicker.viewTime
@ -1857,7 +1976,10 @@ renderEditForm settings model =
, renderItemDateSuggestions model
]
, div [ class " field" ]
[ label [] [ text "Due Date" ]
[ label []
[ Icons.dueDateIcon "grey"
, text "Due Date"
]
, div [ class "ui action input" ]
[ Html.map DueDatePickerMsg
(Comp.DatePicker.viewTime
@ -1871,30 +1993,46 @@ renderEditForm settings model =
, renderDueDateSuggestions model
]
, h4 [ class "ui dividing header" ]
[ i [ class "tiny envelope outline icon" ] []
[ Icons.correspondentIcon
, text "Correspondent"
]
, 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)
, renderOrgSuggestions model
]
, 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)
, renderCorrPersonSuggestions model
]
, h4 [ class "ui dividing header" ]
[ i [ class "tiny comment outline icon" ] []
[ Icons.concernedIcon
, text "Concerning"
]
, 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)
, renderConcPersonSuggestions model
]
, 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)
, renderConcEquipSuggestions model
]

View File

@ -5,10 +5,24 @@ module Data.Icons exposing
, concernedIcon
, correspondent
, correspondentIcon
, date
, dateIcon
, direction
, directionIcon
, dueDate
, dueDateIcon
, editNotes
, editNotesIcon
, equipment
, equipmentIcon
, organization
, organizationIcon
, person
, personIcon
, tag
, tagIcon
, tags
, tagsIcon
)
import Html exposing (Html, i)
@ -35,14 +49,24 @@ correspondentIcon =
i [ class correspondent ] []
date : String
date =
"calendar outline icon"
dateIcon : String -> Html msg
dateIcon classes =
i [ class (date ++ " " ++ classes) ] []
dueDate : String
dueDate =
"bell icon"
dueDateIcon : Html msg
dueDateIcon =
i [ class dueDate ] []
dueDateIcon : String -> Html msg
dueDateIcon classes =
i [ class (dueDate ++ " " ++ classes) ] []
editNotes : String
@ -63,3 +87,63 @@ addFiles =
addFilesIcon : Html msg
addFilesIcon =
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.PersonManage
import Comp.TagManage
import Data.Icons as Icons
import Data.UiSettings exposing (UiSettings)
import Html exposing (..)
import Html.Attributes exposing (..)
@ -25,28 +26,28 @@ view settings model =
[ classActive (model.currentTab == Just TagTab) "link icon item"
, onClick (SetTab TagTab)
]
[ i [ class "tag icon" ] []
[ Icons.tagIcon ""
, text "Tag"
]
, div
[ classActive (model.currentTab == Just EquipTab) "link icon item"
, onClick (SetTab EquipTab)
]
[ i [ class "box icon" ] []
[ Icons.equipmentIcon ""
, text "Equipment"
]
, div
[ classActive (model.currentTab == Just OrgTab) "link icon item"
, onClick (SetTab OrgTab)
]
[ i [ class "factory icon" ] []
[ Icons.organizationIcon ""
, text "Organization"
]
, div
[ classActive (model.currentTab == Just PersonTab) "link icon item"
, onClick (SetTab PersonTab)
]
[ i [ class "user icon" ] []
[ Icons.personIcon ""
, text "Person"
]
]
@ -77,7 +78,7 @@ view settings model =
viewTags : Model -> List (Html Msg)
viewTags model =
[ h2 [ class "ui header" ]
[ i [ class "ui tag icon" ] []
[ Icons.tagIcon ""
, div [ class "content" ]
[ text "Tags"
]
@ -89,7 +90,7 @@ viewTags model =
viewEquip : Model -> List (Html Msg)
viewEquip model =
[ h2 [ class "ui header" ]
[ i [ class "ui box icon" ] []
[ Icons.equipmentIcon ""
, div [ class "content" ]
[ text "Equipment"
]
@ -101,7 +102,7 @@ viewEquip model =
viewOrg : UiSettings -> Model -> List (Html Msg)
viewOrg settings model =
[ h2 [ class "ui header" ]
[ i [ class "ui factory icon" ] []
[ Icons.organizationIcon ""
, div [ class "content" ]
[ text "Organizations"
]
@ -113,7 +114,7 @@ viewOrg settings model =
viewPerson : UiSettings -> Model -> List (Html Msg)
viewPerson settings model =
[ h2 [ class "ui header" ]
[ i [ class "ui user icon" ] []
[ Icons.personIcon ""
, div [ class "content" ]
[ text "Person"
]

View File

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