diff --git a/build.sbt b/build.sbt index ee185406..265a7221 100644 --- a/build.sbt +++ b/build.sbt @@ -198,6 +198,9 @@ val openapiScalaSettings = Seq( case "listtype" => field => field.copy(typeDef = TypeDef("ListType", Imports("docspell.common.ListType"))) + case "personuse" => + field => + field.copy(typeDef = TypeDef("PersonUse", Imports("docspell.common.PersonUse"))) })) ) diff --git a/modules/common/src/main/scala/docspell/common/PersonUse.scala b/modules/common/src/main/scala/docspell/common/PersonUse.scala new file mode 100644 index 00000000..71cd3365 --- /dev/null +++ b/modules/common/src/main/scala/docspell/common/PersonUse.scala @@ -0,0 +1,50 @@ +package docspell.common + +import cats.data.NonEmptyList + +import io.circe.Decoder +import io.circe.Encoder + +sealed trait PersonUse { self: Product => + + final def name: String = + self.productPrefix.toLowerCase() +} + +object PersonUse { + + case object Correspondent extends PersonUse + case object Concerning extends PersonUse + case object Both extends PersonUse + + def concerning: PersonUse = Concerning + def correspondent: PersonUse = Correspondent + def both: PersonUse = Both + + val concerningAndBoth: NonEmptyList[PersonUse] = + NonEmptyList.of(Concerning, Both) + + val correspondentAndBoth: NonEmptyList[PersonUse] = + NonEmptyList.of(Correspondent, Both) + + def fromString(str: String): Either[String, PersonUse] = + str.toLowerCase() match { + case "correspondent" => + Right(Correspondent) + case "concerning" => + Right(Concerning) + case "both" => + Right(Both) + case _ => + Left(s"Unknown person-use: $str") + } + + def unsafeFromString(str: String): PersonUse = + fromString(str).fold(sys.error, identity) + + implicit val jsonDecoder: Decoder[PersonUse] = + Decoder.decodeString.emap(fromString) + + implicit val jsonEncoder: Encoder[PersonUse] = + Encoder.encodeString.contramap(_.name) +} diff --git a/modules/joex/src/main/scala/docspell/joex/process/FindProposal.scala b/modules/joex/src/main/scala/docspell/joex/process/FindProposal.scala index 1bb91af1..42bbb536 100644 --- a/modules/joex/src/main/scala/docspell/joex/process/FindProposal.scala +++ b/modules/joex/src/main/scala/docspell/joex/process/FindProposal.scala @@ -57,7 +57,11 @@ object FindProposal { ctx.store .transact( RPerson - .findLike(coll, mp.values.head.ref.name.toLowerCase, false) + .findLike( + coll, + mp.values.head.ref.name.toLowerCase, + PersonUse.correspondentAndBoth + ) .map(_.headOption) ) .flatTap(oref => @@ -67,7 +71,11 @@ object FindProposal { ctx.store .transact( RPerson - .findLike(coll, mp.values.head.ref.name.toLowerCase, true) + .findLike( + coll, + mp.values.head.ref.name.toLowerCase, + PersonUse.concerningAndBoth + ) .map(_.headOption) ) .flatTap(oref => @@ -231,10 +239,16 @@ object FindProposal { case NerTag.Person => val s1 = ctx.store - .transact(RPerson.findLike(ctx.args.meta.collective, value, true)) + .transact( + RPerson + .findLike(ctx.args.meta.collective, value, PersonUse.concerningAndBoth) + ) .map(MetaProposalList.from(MetaProposalType.ConcPerson, nt)) val s2 = ctx.store - .transact(RPerson.findLike(ctx.args.meta.collective, value, false)) + .transact( + RPerson + .findLike(ctx.args.meta.collective, value, PersonUse.correspondentAndBoth) + ) .map(MetaProposalList.from(MetaProposalType.CorrPerson, nt)) val s3 = ctx.store @@ -288,10 +302,16 @@ object FindProposal { .transact(ROrganization.findLike(ctx.args.meta.collective, kind, value)) .map(MetaProposalList.from(MetaProposalType.CorrOrg, nt)) val corrP = ctx.store - .transact(RPerson.findLike(ctx.args.meta.collective, kind, value, false)) + .transact( + RPerson + .findLike(ctx.args.meta.collective, kind, value, PersonUse.correspondentAndBoth) + ) .map(MetaProposalList.from(MetaProposalType.CorrPerson, nt)) val concP = ctx.store - .transact(RPerson.findLike(ctx.args.meta.collective, kind, value, true)) + .transact( + RPerson + .findLike(ctx.args.meta.collective, kind, value, PersonUse.concerningAndBoth) + ) .map(MetaProposalList.from(MetaProposalType.CorrPerson, nt)) ctx.logger.debug(s"Looking with $kind: $value") *> diff --git a/modules/joex/src/main/scala/docspell/joex/scanmailbox/ScanMailboxTask.scala b/modules/joex/src/main/scala/docspell/joex/scanmailbox/ScanMailboxTask.scala index acb91c00..741f2a00 100644 --- a/modules/joex/src/main/scala/docspell/joex/scanmailbox/ScanMailboxTask.scala +++ b/modules/joex/src/main/scala/docspell/joex/scanmailbox/ScanMailboxTask.scala @@ -236,7 +236,7 @@ object ScanMailboxTask { ctx.args.account.collective, from.address, Some(ContactKind.Email), - Some(true) + Some(NonEmptyList.of(PersonUse.concerning)) ) .take(1) .compile diff --git a/modules/restapi/src/main/resources/docspell-openapi.yml b/modules/restapi/src/main/resources/docspell-openapi.yml index deb96ef4..9ac23cd8 100644 --- a/modules/restapi/src/main/resources/docspell-openapi.yml +++ b/modules/restapi/src/main/resources/docspell-openapi.yml @@ -4999,7 +4999,7 @@ components: - address - contacts - created - - concerning + - use properties: id: type: string @@ -5016,11 +5016,16 @@ components: $ref: "#/components/schemas/Contact" notes: type: string - concerning: - type: boolean + use: + type: string + format: personuse + enum: + - concerning + - correspondent + - both description: | Whether this person should be used to create suggestions - for the "concerning person" association. + for the "concerning person", "correspondent" or both. created: description: DateTime type: integer diff --git a/modules/restserver/src/main/scala/docspell/restserver/conv/Conversions.scala b/modules/restserver/src/main/scala/docspell/restserver/conv/Conversions.scala index eefaa9cb..ddd36923 100644 --- a/modules/restserver/src/main/scala/docspell/restserver/conv/Conversions.scala +++ b/modules/restserver/src/main/scala/docspell/restserver/conv/Conversions.scala @@ -445,7 +445,7 @@ trait Conversions { Address(rp.street, rp.zip, rp.city, rp.country), v.contacts.map(mkContact).toList, rp.notes, - rp.concerning, + rp.use, rp.created ) } @@ -466,10 +466,10 @@ trait Conversions { v.address.city, v.address.country, v.notes, - v.concerning, now, now, - v.organization.map(_.id) + v.organization.map(_.id), + v.use ) } yield OOrganization.PersonAndContacts(pers, None, cont) } @@ -492,10 +492,10 @@ trait Conversions { v.address.city, v.address.country, v.notes, - v.concerning, v.created, now, - v.organization.map(_.id) + v.organization.map(_.id), + v.use ) } yield OOrganization.PersonAndContacts(pers, None, cont) } diff --git a/modules/store/src/main/resources/db/migration/h2/V1.20.0__personuse.sql b/modules/store/src/main/resources/db/migration/h2/V1.20.0__personuse.sql new file mode 100644 index 00000000..ab86ef52 --- /dev/null +++ b/modules/store/src/main/resources/db/migration/h2/V1.20.0__personuse.sql @@ -0,0 +1,9 @@ +ALTER TABLE "person" +ADD COLUMN "person_use" varchar(254); + +UPDATE "person" SET "person_use" = 'concerning' where "concerning" = true; +UPDATE "person" SET "person_use" = 'correspondent' where "concerning" = false; +UPDATE "person" SET "person_use" = 'both' where "concerning" is null; + +ALTER TABLE "person" +DROP COLUMN "concerning"; diff --git a/modules/store/src/main/resources/db/migration/mariadb/V1.20.0__personuse.sql b/modules/store/src/main/resources/db/migration/mariadb/V1.20.0__personuse.sql new file mode 100644 index 00000000..e3418e6c --- /dev/null +++ b/modules/store/src/main/resources/db/migration/mariadb/V1.20.0__personuse.sql @@ -0,0 +1,9 @@ +ALTER TABLE `person` +ADD COLUMN `person_use` varchar(254); + +UPDATE `person` SET `person_use` = 'concerning' where `concerning` = true; +UPDATE `person` SET `person_use` = 'correspondent' where `concerning` = false; +UPDATE `person` SET `person_use` = 'both' where `concerning` is null; + +ALTER TABLE `person` +DROP COLUMN `concerning`; diff --git a/modules/store/src/main/resources/db/migration/postgresql/V1.20.0__personuse.sql b/modules/store/src/main/resources/db/migration/postgresql/V1.20.0__personuse.sql new file mode 100644 index 00000000..ab86ef52 --- /dev/null +++ b/modules/store/src/main/resources/db/migration/postgresql/V1.20.0__personuse.sql @@ -0,0 +1,9 @@ +ALTER TABLE "person" +ADD COLUMN "person_use" varchar(254); + +UPDATE "person" SET "person_use" = 'concerning' where "concerning" = true; +UPDATE "person" SET "person_use" = 'correspondent' where "concerning" = false; +UPDATE "person" SET "person_use" = 'both' where "concerning" is null; + +ALTER TABLE "person" +DROP COLUMN "concerning"; diff --git a/modules/store/src/main/scala/docspell/store/impl/DoobieMeta.scala b/modules/store/src/main/scala/docspell/store/impl/DoobieMeta.scala index 8952891f..e38e8334 100644 --- a/modules/store/src/main/scala/docspell/store/impl/DoobieMeta.scala +++ b/modules/store/src/main/scala/docspell/store/impl/DoobieMeta.scala @@ -103,6 +103,9 @@ trait DoobieMeta extends EmilDoobieMeta { implicit val metaListType: Meta[ListType] = Meta[String].timap(ListType.unsafeFromString)(_.name) + + implicit val metaPersonUse: Meta[PersonUse] = + Meta[String].timap(PersonUse.unsafeFromString)(_.name) } object DoobieMeta extends DoobieMeta { diff --git a/modules/store/src/main/scala/docspell/store/queries/QOrganization.scala b/modules/store/src/main/scala/docspell/store/queries/QOrganization.scala index dc3c13fd..a966c90a 100644 --- a/modules/store/src/main/scala/docspell/store/queries/QOrganization.scala +++ b/modules/store/src/main/scala/docspell/store/queries/QOrganization.scala @@ -1,5 +1,6 @@ package docspell.store.queries +import cats.data.NonEmptyList import cats.implicits._ import fs2._ @@ -121,13 +122,13 @@ object QOrganization { coll: Ident, value: String, ck: Option[ContactKind], - concerning: Option[Boolean] + use: Option[NonEmptyList[PersonUse]] ): Stream[ConnectionIO, RPerson] = runDistinct( select(p.all), from(p).innerJoin(c, c.personId === p.pid), c.value.like(s"%${value.toLowerCase}%") && p.cid === coll &&? - concerning.map(c => p.concerning === c) &&? + use.map(u => p.use.in(u)) &&? ck.map(k => c.kind === k) ).query[RPerson].stream diff --git a/modules/store/src/main/scala/docspell/store/records/RPerson.scala b/modules/store/src/main/scala/docspell/store/records/RPerson.scala index 8f265a48..e2552b53 100644 --- a/modules/store/src/main/scala/docspell/store/records/RPerson.scala +++ b/modules/store/src/main/scala/docspell/store/records/RPerson.scala @@ -21,10 +21,10 @@ case class RPerson( city: String, country: String, notes: Option[String], - concerning: Boolean, created: Timestamp, updated: Timestamp, - oid: Option[Ident] + oid: Option[Ident], + use: PersonUse ) {} object RPerson { @@ -34,18 +34,18 @@ object RPerson { final case class Table(alias: Option[String]) extends TableDef { val tableName = "person" - val pid = Column[Ident]("pid", this) - val cid = Column[Ident]("cid", this) - val name = Column[String]("name", this) - val street = Column[String]("street", this) - val zip = Column[String]("zip", this) - val city = Column[String]("city", this) - val country = Column[String]("country", this) - val notes = Column[String]("notes", this) - val concerning = Column[Boolean]("concerning", this) - val created = Column[Timestamp]("created", this) - val updated = Column[Timestamp]("updated", this) - val oid = Column[Ident]("oid", this) + val pid = Column[Ident]("pid", this) + val cid = Column[Ident]("cid", this) + val name = Column[String]("name", this) + val street = Column[String]("street", this) + val zip = Column[String]("zip", this) + val city = Column[String]("city", this) + val country = Column[String]("country", this) + val notes = Column[String]("notes", this) + val created = Column[Timestamp]("created", this) + val updated = Column[Timestamp]("updated", this) + val oid = Column[Ident]("oid", this) + val use = Column[PersonUse]("person_use", this) val all = NonEmptyList.of[Column[_]]( pid, cid, @@ -55,10 +55,10 @@ object RPerson { city, country, notes, - concerning, created, updated, - oid + oid, + use ) } @@ -70,7 +70,7 @@ object RPerson { DML.insert( T, T.all, - fr"${v.pid},${v.cid},${v.name},${v.street},${v.zip},${v.city},${v.country},${v.notes},${v.concerning},${v.created},${v.updated},${v.oid}" + fr"${v.pid},${v.cid},${v.name},${v.street},${v.zip},${v.city},${v.country},${v.notes},${v.created},${v.updated},${v.oid},${v.use}" ) def update(v: RPerson): ConnectionIO[Int] = { @@ -85,7 +85,7 @@ object RPerson { T.zip.setTo(v.zip), T.city.setTo(v.city), T.country.setTo(v.country), - T.concerning.setTo(v.concerning), + T.use.setTo(v.use), T.notes.setTo(v.notes), T.oid.setTo(v.oid), T.updated.setTo(now) @@ -116,19 +116,19 @@ object RPerson { def findLike( coll: Ident, personName: String, - concerningOnly: Boolean + use: NonEmptyList[PersonUse] ): ConnectionIO[Vector[IdRef]] = run( select(T.pid, T.name), from(T), - where(T.cid === coll, T.concerning === concerningOnly, T.name.like(personName)) + where(T.cid === coll, T.use.in(use), T.name.like(personName)) ).query[IdRef].to[Vector] def findLike( coll: Ident, contactKind: ContactKind, value: String, - concerningOnly: Boolean + use: NonEmptyList[PersonUse] ): ConnectionIO[Vector[IdRef]] = { val p = RPerson.as("p") val c = RContact.as("c") @@ -139,7 +139,7 @@ object RPerson { where( p.cid === coll, c.kind === contactKind, - p.concerning === concerningOnly, + p.use.in(use), c.value.like(value) ) ).query[IdRef].to[Vector] diff --git a/modules/webapp/src/main/elm/Comp/DateInput.elm b/modules/webapp/src/main/elm/Comp/DateInput.elm new file mode 100644 index 00000000..cfc8602d --- /dev/null +++ b/modules/webapp/src/main/elm/Comp/DateInput.elm @@ -0,0 +1,4 @@ +module Comp.DateInput exposing (..) + +import Html exposing (..) +import Html.Attributes exposing (..) diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/MultiEditMenu.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/MultiEditMenu.elm index 20fdde6f..d20e697f 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail/MultiEditMenu.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail/MultiEditMenu.elm @@ -32,6 +32,7 @@ import Data.DropdownStyle import Data.Fields import Data.Flags exposing (Flags) import Data.Icons as Icons +import Data.PersonUse import Data.UiSettings exposing (UiSettings) import DatePicker exposing (DatePicker) import Html exposing (..) @@ -429,14 +430,14 @@ update flags msg model = GetPersonResp (Ok ps) -> let - ( conc, corr ) = - List.partition .concerning ps.items + { concerning, correspondent } = + Data.PersonUse.spanPersonList ps.items concRefs = - List.map (\e -> IdName e.id e.name) conc + List.map (\e -> IdName e.id e.name) concerning corrRefs = - List.map (\e -> IdName e.id e.name) corr + List.map (\e -> IdName e.id e.name) correspondent res1 = update flags (CorrPersonMsg (Comp.Dropdown.SetOptions corrRefs)) model diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm index 0b24751c..0dcc4043 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm @@ -49,6 +49,7 @@ import Data.Direction import Data.Fields exposing (Field) import Data.Flags exposing (Flags) import Data.ItemNav exposing (ItemNav) +import Data.PersonUse import Data.UiSettings exposing (UiSettings) import DatePicker import Dict @@ -612,8 +613,8 @@ update key flags inav settings msg model = GetPersonResp (Ok ps) -> let - ( conc, corr ) = - List.partition .concerning ps.items + { concerning, correspondent } = + Data.PersonUse.spanPersonList ps.items personDict = List.map (\p -> ( p.id, p )) ps.items @@ -632,10 +633,10 @@ update key flags inav settings msg model = \_ -> True concRefs = - List.map (\e -> IdName e.id e.name) conc + List.map (\e -> IdName e.id e.name) concerning corrRefs = - List.filter personFilter corr + List.filter personFilter correspondent |> List.map (\e -> IdName e.id e.name) mkPersonOption idref = diff --git a/modules/webapp/src/main/elm/Comp/PersonForm.elm b/modules/webapp/src/main/elm/Comp/PersonForm.elm index dded098c..9ed8b2be 100644 --- a/modules/webapp/src/main/elm/Comp/PersonForm.elm +++ b/modules/webapp/src/main/elm/Comp/PersonForm.elm @@ -16,12 +16,14 @@ import Comp.AddressForm import Comp.Basic as B import Comp.ContactField import Comp.Dropdown +import Comp.FixedDropdown import Data.DropdownStyle as DS import Data.Flags exposing (Flags) +import Data.PersonUse exposing (PersonUse) import Data.UiSettings exposing (UiSettings) import Html exposing (..) import Html.Attributes exposing (..) -import Html.Events exposing (onCheck, onInput) +import Html.Events exposing (onInput) import Styles as S @@ -31,7 +33,8 @@ type alias Model = , addressModel : Comp.AddressForm.Model , contactModel : Comp.ContactField.Model , notes : Maybe String - , concerning : Bool + , use : PersonUse + , useModel : Comp.FixedDropdown.Model PersonUse , orgModel : Comp.Dropdown.Model IdName } @@ -43,7 +46,11 @@ emptyModel = , addressModel = Comp.AddressForm.emptyModel , contactModel = Comp.ContactField.emptyModel , notes = Nothing - , concerning = False + , use = Data.PersonUse.Both + , useModel = + Comp.FixedDropdown.initMap + Data.PersonUse.label + Data.PersonUse.all , orgModel = Comp.Dropdown.orgDropdown } @@ -68,7 +75,7 @@ getPerson model = , address = Comp.AddressForm.getAddress model.addressModel , contacts = Comp.ContactField.getContacts model.contactModel , notes = model.notes - , concerning = model.concerning + , use = Data.PersonUse.asString model.use , organization = org } @@ -79,9 +86,9 @@ type Msg | AddressMsg Comp.AddressForm.Msg | ContactMsg Comp.ContactField.Msg | SetNotes String - | SetConcerning Bool | SetOrgs (List IdName) | OrgDropdownMsg (Comp.Dropdown.Msg IdName) + | UseDropdownMsg (Comp.FixedDropdown.Msg PersonUse) update : Flags -> Msg -> Model -> ( Model, Cmd Msg ) @@ -108,7 +115,9 @@ update flags msg model = | person = t , name = t.name , notes = t.notes - , concerning = t.concerning + , use = + Data.PersonUse.fromString t.use + |> Maybe.withDefault Data.PersonUse.Both } , Cmd.batch [ c1, c2, c3 ] ) @@ -149,8 +158,15 @@ update flags msg model = , Cmd.none ) - SetConcerning _ -> - ( { model | concerning = not model.concerning }, Cmd.none ) + UseDropdownMsg lm -> + let + ( nm, mu ) = + Comp.FixedDropdown.update lm model.useModel + + newUse = + Maybe.withDefault model.use mu + in + ( { model | useModel = nm, use = newUse }, Cmd.none ) OrgDropdownMsg lm -> let @@ -185,16 +201,10 @@ view1 settings compact model = ] [] ] - , div [ class "inline field" ] - [ div [ class "ui checkbox" ] - [ input - [ type_ "checkbox" - , checked model.concerning - , onCheck SetConcerning - ] - [] - , label [] [ text "Use for concerning person suggestion only" ] - ] + , div [ class "field" ] + [ label [] [ text "Use" ] + , Html.map UseDropdownMsg (Comp.FixedDropdown.view (makeUseItem model) model.useModel) + , label [] [ text "Use for concerning person suggestion only" ] ] , div [ class "field" ] [ label [] [ text "Organization" ] @@ -221,6 +231,12 @@ view1 settings compact model = ] +makeUseItem : Model -> Maybe (Comp.FixedDropdown.Item PersonUse) +makeUseItem model = + Just <| + Comp.FixedDropdown.Item model.use (Data.PersonUse.label model.use) + + --- View2 @@ -253,21 +269,21 @@ view2 mobile settings model = ] , div [ class "mb-4" ] [ label - [ class "inline-flex items-center" - , for "concerning" + [ class S.inputLabel ] - [ input - [ type_ "checkbox" - , checked model.concerning - , onCheck SetConcerning - , class S.checkboxInput - , name "concerning" - , id "concerning" - ] - [] - , span [ class "ml-2" ] - [ text "Use for concerning person suggestion only" - ] + [ text "Use of this person" ] + , Html.map UseDropdownMsg + (Comp.FixedDropdown.view2 (makeUseItem model) model.useModel) + , span [ class "opacity-50 text-sm" ] + [ case model.use of + Data.PersonUse.Concerning -> + text "Use as concerning person only" + + Data.PersonUse.Correspondent -> + text "Use as correspondent person only" + + Data.PersonUse.Both -> + text "Use as both concerning or correspondent person" ] ] , div [ class "mb-4" ] diff --git a/modules/webapp/src/main/elm/Comp/PersonTable.elm b/modules/webapp/src/main/elm/Comp/PersonTable.elm index 8aa3f89e..2d1818e1 100644 --- a/modules/webapp/src/main/elm/Comp/PersonTable.elm +++ b/modules/webapp/src/main/elm/Comp/PersonTable.elm @@ -10,6 +10,7 @@ module Comp.PersonTable exposing import Api.Model.Person exposing (Person) import Comp.Basic as B import Data.Flags exposing (Flags) +import Data.PersonUse import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (onClick) @@ -57,7 +58,7 @@ view model = [ thead [] [ tr [] [ th [ class "collapsing" ] [] - , th [ class "collapsing center aligned" ] [ text "Concerning" ] + , th [ class "collapsing center aligned" ] [ text "Use" ] , th [] [ text "Name" ] , th [] [ text "Organization" ] , th [] [ text "Address" ] @@ -85,11 +86,10 @@ renderPersonLine model person = ] ] , td [ class "center aligned" ] - [ if person.concerning then - i [ class "check square outline icon" ] [] - - else - i [ class "minus square outline icon" ] [] + [ Data.PersonUse.fromString person.use + |> Maybe.withDefault Data.PersonUse.Both + |> Data.PersonUse.label + |> text ] , td [] [ text person.name @@ -118,8 +118,8 @@ view2 model = [ thead [] [ tr [] [ th [ class "w-px whitespace-nowrap" ] [] - , th [ class "w-px whitespace-nowrap text-center pr-1 md:px-2" ] - [ text "Concerning" + , th [ class "text-left pr-1 md:px-2" ] + [ text "Use" ] , th [ class "text-left" ] [ text "Name" ] , th [ class "text-left hidden sm:table-cell" ] [ text "Organization" ] @@ -138,8 +138,13 @@ renderPersonLine2 model person = , class S.tableRow ] [ B.editLinkTableCell (Select person) - , td [ class "w-px whitespace-nowrap text-center" ] - [ Util.Html.checkbox2 person.concerning + , td [ class "text-left pr-1 md:px-2" ] + [ div [ class "label inline-flex text-sm" ] + [ Data.PersonUse.fromString person.use + |> Maybe.withDefault Data.PersonUse.Both + |> Data.PersonUse.label + |> text + ] ] , td [] [ text person.name diff --git a/modules/webapp/src/main/elm/Comp/SearchMenu.elm b/modules/webapp/src/main/elm/Comp/SearchMenu.elm index a94185e9..140147af 100644 --- a/modules/webapp/src/main/elm/Comp/SearchMenu.elm +++ b/modules/webapp/src/main/elm/Comp/SearchMenu.elm @@ -38,6 +38,7 @@ import Data.DropdownStyle as DS import Data.Fields import Data.Flags exposing (Flags) import Data.Icons as Icons +import Data.PersonUse import Data.UiSettings exposing (UiSettings) import DatePicker exposing (DatePicker) import Html exposing (..) @@ -561,14 +562,14 @@ updateDrop ddm flags settings msg model = GetPersonResp (Ok ps) -> let - ( conc, corr ) = - List.partition .concerning ps.items + { concerning, correspondent } = + Data.PersonUse.spanPersonList ps.items concRefs = - List.map (\e -> IdName e.id e.name) conc + List.map (\e -> IdName e.id e.name) concerning corrRefs = - List.map (\e -> IdName e.id e.name) corr + List.map (\e -> IdName e.id e.name) correspondent next1 = updateDrop ddm diff --git a/modules/webapp/src/main/elm/Data/PersonUse.elm b/modules/webapp/src/main/elm/Data/PersonUse.elm new file mode 100644 index 00000000..c00342a4 --- /dev/null +++ b/modules/webapp/src/main/elm/Data/PersonUse.elm @@ -0,0 +1,90 @@ +module Data.PersonUse exposing + ( PersonUse(..) + , all + , asString + , fromString + , label + , spanPersonList + ) + +import Api.Model.Person exposing (Person) + + +type PersonUse + = Correspondent + | Concerning + | Both + + +fromString : String -> Maybe PersonUse +fromString str = + case String.toLower str of + "concerning" -> + Just Concerning + + "correspondent" -> + Just Correspondent + + "both" -> + Just Both + + _ -> + Nothing + + +asString : PersonUse -> String +asString pu = + case pu of + Correspondent -> + "correspondent" + + Concerning -> + "concerning" + + Both -> + "both" + + +label : PersonUse -> String +label pu = + case pu of + Correspondent -> + "Correspondent" + + Concerning -> + "Concerning" + + Both -> + "Both" + + +all : List PersonUse +all = + [ Correspondent, Concerning, Both ] + + +spanPersonList : List Person -> { concerning : List Person, correspondent : List Person } +spanPersonList input = + let + init = + { concerning = [], correspondent = [] } + + parseUse p = + fromString p.use + |> Maybe.withDefault Both + + merge p res = + case parseUse p of + Concerning -> + { res | concerning = p :: res.concerning } + + Correspondent -> + { res | correspondent = p :: res.correspondent } + + Both -> + { res + | correspondent = p :: res.correspondent + , concerning = p :: res.concerning + } + in + List.foldl merge init input