mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-04-05 10:59:33 +00:00
commit
7e4c0b3e42
@ -28,8 +28,10 @@ trait OOrganization[F[_]] {
|
||||
|
||||
def findAllPersonRefs(account: AccountId, nameQuery: Option[String]): F[Vector[IdRef]]
|
||||
|
||||
/** Add a new person with their contacts. The additional organization is ignored. */
|
||||
def addPerson(s: PersonAndContacts): F[AddResult]
|
||||
|
||||
/** Update a person with their contacts. The additional organization is ignored. */
|
||||
def updatePerson(s: PersonAndContacts): F[AddResult]
|
||||
|
||||
def deleteOrg(orgId: Ident, collective: Ident): F[AddResult]
|
||||
@ -41,7 +43,11 @@ object OOrganization {
|
||||
|
||||
case class OrgAndContacts(org: ROrganization, contacts: Seq[RContact])
|
||||
|
||||
case class PersonAndContacts(person: RPerson, contacts: Seq[RContact])
|
||||
case class PersonAndContacts(
|
||||
person: RPerson,
|
||||
org: Option[ROrganization],
|
||||
contacts: Seq[RContact]
|
||||
)
|
||||
|
||||
def apply[F[_]: Effect](store: Store[F]): Resource[F, OOrganization[F]] =
|
||||
Resource.pure[F, OOrganization[F]](new OOrganization[F] {
|
||||
@ -79,14 +85,14 @@ object OOrganization {
|
||||
): F[Vector[PersonAndContacts]] =
|
||||
store
|
||||
.transact(QOrganization.findPersonAndContact(account.collective, query, _.name))
|
||||
.map({ case (person, cont) => PersonAndContacts(person, cont) })
|
||||
.map({ case (person, org, cont) => PersonAndContacts(person, org, cont) })
|
||||
.compile
|
||||
.toVector
|
||||
|
||||
def findPerson(account: AccountId, persId: Ident): F[Option[PersonAndContacts]] =
|
||||
store
|
||||
.transact(QOrganization.getPersonAndContact(account.collective, persId))
|
||||
.map(_.map({ case (org, cont) => PersonAndContacts(org, cont) }))
|
||||
.map(_.map({ case (pers, org, cont) => PersonAndContacts(pers, org, cont) }))
|
||||
|
||||
def findAllPersonRefs(
|
||||
account: AccountId,
|
||||
|
@ -0,0 +1,18 @@
|
||||
package docspell.common
|
||||
|
||||
import io.circe._
|
||||
import io.circe.generic.semiauto._
|
||||
|
||||
case class PersonRef(id: Ident, name: String, organization: Option[Ident]) {
|
||||
|
||||
def toIdRef: IdRef =
|
||||
IdRef(id, name)
|
||||
}
|
||||
|
||||
object PersonRef {
|
||||
|
||||
implicit val jsonEncoder: Encoder[PersonRef] =
|
||||
deriveEncoder[PersonRef]
|
||||
implicit val jsonDecoder: Decoder[PersonRef] =
|
||||
deriveDecoder[PersonRef]
|
||||
}
|
@ -6,8 +6,8 @@ import cats.effect.Sync
|
||||
import cats.implicits._
|
||||
|
||||
import docspell.common._
|
||||
import docspell.joex.scheduler.Task
|
||||
import docspell.store.records.RAttachmentMeta
|
||||
import docspell.joex.scheduler.{Context, Task}
|
||||
import docspell.store.records.{RAttachmentMeta, RPerson}
|
||||
|
||||
/** Calculate weights for candidates that adds the most likely
|
||||
* candidate a lower number.
|
||||
@ -15,21 +15,40 @@ import docspell.store.records.RAttachmentMeta
|
||||
object EvalProposals {
|
||||
|
||||
def apply[F[_]: Sync](data: ItemData): Task[F, ProcessItemArgs, ItemData] =
|
||||
Task { _ =>
|
||||
Timestamp
|
||||
.current[F]
|
||||
.map { now =>
|
||||
val metas = data.metas.map(calcCandidateWeight(now.toUtcDate))
|
||||
data.copy(metas = metas)
|
||||
}
|
||||
Task { ctx =>
|
||||
for {
|
||||
now <- Timestamp.current[F]
|
||||
personRefs <- findOrganizationRelation[F](data, ctx)
|
||||
metas = data.metas.map(calcCandidateWeight(now.toUtcDate, personRefs))
|
||||
} yield data.copy(metas = metas)
|
||||
}
|
||||
|
||||
def calcCandidateWeight(now: LocalDate)(rm: RAttachmentMeta): RAttachmentMeta = {
|
||||
val list = rm.proposals.change(mp => mp.addWeights(weight(rm, mp, now)))
|
||||
def findOrganizationRelation[F[_]: Sync](
|
||||
data: ItemData,
|
||||
ctx: Context[F, _]
|
||||
): F[Map[Ident, PersonRef]] = {
|
||||
val corrPersIds = data.metas
|
||||
.flatMap(_.proposals.find(MetaProposalType.CorrPerson))
|
||||
.flatMap(_.values.toList.map(_.ref.id))
|
||||
.toSet
|
||||
ctx.store
|
||||
.transact(RPerson.findOrganization(corrPersIds))
|
||||
.map(_.map(p => (p.id, p)).toMap)
|
||||
}
|
||||
|
||||
def calcCandidateWeight(now: LocalDate, personRefs: Map[Ident, PersonRef])(
|
||||
rm: RAttachmentMeta
|
||||
): RAttachmentMeta = {
|
||||
val list = rm.proposals.change(mp => mp.addWeights(weight(rm, mp, now, personRefs)))
|
||||
rm.copy(proposals = list.sortByWeights)
|
||||
}
|
||||
|
||||
def weight(rm: RAttachmentMeta, mp: MetaProposal, ref: LocalDate)(
|
||||
def weight(
|
||||
rm: RAttachmentMeta,
|
||||
mp: MetaProposal,
|
||||
ref: LocalDate,
|
||||
personRefs: Map[Ident, PersonRef]
|
||||
)(
|
||||
cand: MetaProposal.Candidate
|
||||
): Double =
|
||||
mp.proposalType match {
|
||||
@ -51,7 +70,27 @@ object EvalProposals {
|
||||
val words = cand.origin.map(_.label.split(' ').length).max.toDouble
|
||||
val nerFac =
|
||||
cand.origin.map(label => nerTagFactor(label.tag, mp.proposalType)).min
|
||||
(1 / words) * (1 / tagCount) * positionWeight(pos, textLen) * nerFac
|
||||
val corrPerFac = corrOrgPersonFactor(rm, mp, personRefs, cand)
|
||||
(1 / words) * (1 / tagCount) * positionWeight(pos, textLen) * nerFac * corrPerFac
|
||||
}
|
||||
|
||||
def corrOrgPersonFactor(
|
||||
rm: RAttachmentMeta,
|
||||
mp: MetaProposal,
|
||||
personRefs: Map[Ident, PersonRef],
|
||||
cand: MetaProposal.Candidate
|
||||
): Double =
|
||||
mp.proposalType match {
|
||||
case MetaProposalType.CorrPerson =>
|
||||
(for {
|
||||
currentOrg <- rm.proposals
|
||||
.find(MetaProposalType.CorrOrg)
|
||||
.map(_.values.head.ref.id)
|
||||
personOrg <- personRefs.get(cand.ref.id).flatMap(_.organization)
|
||||
fac = if (currentOrg == personOrg) 0.5 else 1
|
||||
} yield fac).getOrElse(1)
|
||||
case _ =>
|
||||
1
|
||||
}
|
||||
|
||||
def positionWeight(pos: Int, total: Int): Double =
|
||||
|
@ -4833,6 +4833,8 @@ components:
|
||||
format: ident
|
||||
name:
|
||||
type: string
|
||||
organization:
|
||||
$ref: "#/components/schemas/IdName"
|
||||
address:
|
||||
$ref: "#/components/schemas/Address"
|
||||
contacts:
|
||||
|
@ -414,15 +414,16 @@ trait Conversions {
|
||||
}
|
||||
|
||||
def mkPerson(v: OOrganization.PersonAndContacts): Person = {
|
||||
val ro = v.person
|
||||
val rp = v.person
|
||||
Person(
|
||||
ro.pid,
|
||||
ro.name,
|
||||
Address(ro.street, ro.zip, ro.city, ro.country),
|
||||
rp.pid,
|
||||
rp.name,
|
||||
v.org.map(o => IdName(o.oid, o.name)),
|
||||
Address(rp.street, rp.zip, rp.city, rp.country),
|
||||
v.contacts.map(mkContact).toList,
|
||||
ro.notes,
|
||||
ro.concerning,
|
||||
ro.created
|
||||
rp.notes,
|
||||
rp.concerning,
|
||||
rp.created
|
||||
)
|
||||
}
|
||||
|
||||
@ -433,7 +434,7 @@ trait Conversions {
|
||||
now <- Timestamp.current[F]
|
||||
pid <- Ident.randomId[F]
|
||||
cont <- contacts(pid)
|
||||
org = RPerson(
|
||||
pers = RPerson(
|
||||
pid,
|
||||
cid,
|
||||
v.name,
|
||||
@ -444,9 +445,10 @@ trait Conversions {
|
||||
v.notes,
|
||||
v.concerning,
|
||||
now,
|
||||
now
|
||||
now,
|
||||
v.organization.map(_.id)
|
||||
)
|
||||
} yield OOrganization.PersonAndContacts(org, cont)
|
||||
} yield OOrganization.PersonAndContacts(pers, None, cont)
|
||||
}
|
||||
|
||||
def changePerson[F[_]: Sync](
|
||||
@ -458,7 +460,7 @@ trait Conversions {
|
||||
for {
|
||||
now <- Timestamp.current[F]
|
||||
cont <- contacts(v.id)
|
||||
org = RPerson(
|
||||
pers = RPerson(
|
||||
v.id,
|
||||
cid,
|
||||
v.name,
|
||||
@ -469,9 +471,10 @@ trait Conversions {
|
||||
v.notes,
|
||||
v.concerning,
|
||||
v.created,
|
||||
now
|
||||
now,
|
||||
v.organization.map(_.id)
|
||||
)
|
||||
} yield OOrganization.PersonAndContacts(org, cont)
|
||||
} yield OOrganization.PersonAndContacts(pers, None, cont)
|
||||
}
|
||||
|
||||
// contact
|
||||
|
@ -0,0 +1,7 @@
|
||||
ALTER TABLE "person"
|
||||
ADD COLUMN "oid" varchar(254);
|
||||
|
||||
ALTER TABLE "person"
|
||||
ADD CONSTRAINT fk_person_organization
|
||||
FOREIGN KEY ("oid")
|
||||
REFERENCES "organization"("oid");
|
@ -0,0 +1,7 @@
|
||||
ALTER TABLE `person`
|
||||
ADD COLUMN `oid` varchar(254);
|
||||
|
||||
ALTER TABLE `person`
|
||||
ADD CONSTRAINT fk_person_organization
|
||||
FOREIGN KEY (`oid`)
|
||||
REFERENCES `organization`(`oid`);
|
@ -0,0 +1,7 @@
|
||||
ALTER TABLE "person"
|
||||
ADD COLUMN "oid" varchar(254);
|
||||
|
||||
ALTER TABLE "person"
|
||||
ADD CONSTRAINT fk_person_organization
|
||||
FOREIGN KEY ("oid")
|
||||
REFERENCES "organization"("oid");
|
@ -41,7 +41,7 @@ object QOrganization {
|
||||
Seq.empty
|
||||
})
|
||||
|
||||
(selectSimple(cols, from, and(q)) ++ orderBy(order(OC).f))
|
||||
(selectSimple(cols, from, and(q)) ++ orderBy(order(OC).prefix("o").f))
|
||||
.query[(ROrganization, Option[RContact])]
|
||||
.stream
|
||||
.groupAdjacentBy(_._1)
|
||||
@ -82,17 +82,21 @@ object QOrganization {
|
||||
coll: Ident,
|
||||
query: Option[String],
|
||||
order: PC.type => Column
|
||||
): Stream[ConnectionIO, (RPerson, Vector[RContact])] = {
|
||||
): Stream[ConnectionIO, (RPerson, Option[ROrganization], Vector[RContact])] = {
|
||||
val pColl = PC.cid.prefix("p")
|
||||
val pName = RPerson.Columns.name.prefix("p")
|
||||
val pNotes = RPerson.Columns.notes.prefix("p")
|
||||
val pId = RPerson.Columns.pid.prefix("p")
|
||||
val cPers = RContact.Columns.personId.prefix("c")
|
||||
val cVal = RContact.Columns.value.prefix("c")
|
||||
val oId = ROrganization.Columns.oid.prefix("o")
|
||||
val pOid = RPerson.Columns.oid.prefix("p")
|
||||
|
||||
val cols = RPerson.Columns.all.map(_.prefix("p")) ++ RContact.Columns.all
|
||||
.map(_.prefix("c"))
|
||||
val cols = RPerson.Columns.all.map(_.prefix("p")) ++
|
||||
ROrganization.Columns.all.map(_.prefix("o")) ++
|
||||
RContact.Columns.all.map(_.prefix("c"))
|
||||
val from = RPerson.table ++ fr"p LEFT JOIN" ++
|
||||
ROrganization.table ++ fr"o ON" ++ pOid.is(oId) ++ fr"LEFT JOIN" ++
|
||||
RContact.table ++ fr"c ON" ++ cPers.is(pId)
|
||||
|
||||
val q = Seq(pColl.is(coll)) ++ (query match {
|
||||
@ -103,38 +107,44 @@ object QOrganization {
|
||||
Seq.empty
|
||||
})
|
||||
|
||||
(selectSimple(cols, from, and(q)) ++ orderBy(order(PC).f))
|
||||
.query[(RPerson, Option[RContact])]
|
||||
(selectSimple(cols, from, and(q)) ++ orderBy(order(PC).prefix("p").f))
|
||||
.query[(RPerson, Option[ROrganization], Option[RContact])]
|
||||
.stream
|
||||
.groupAdjacentBy(_._1)
|
||||
.map({ case (ro, chunk) =>
|
||||
val cs = chunk.toVector.flatMap(_._2)
|
||||
(ro, cs)
|
||||
.map({ case (rp, chunk) =>
|
||||
val cs = chunk.toVector.flatMap(_._3)
|
||||
val ro = chunk.map(_._2).head.flatten
|
||||
(rp, ro, cs)
|
||||
})
|
||||
}
|
||||
|
||||
def getPersonAndContact(
|
||||
coll: Ident,
|
||||
persId: Ident
|
||||
): ConnectionIO[Option[(RPerson, Vector[RContact])]] = {
|
||||
): ConnectionIO[Option[(RPerson, Option[ROrganization], Vector[RContact])]] = {
|
||||
val pColl = PC.cid.prefix("p")
|
||||
val pId = RPerson.Columns.pid.prefix("p")
|
||||
val cPers = RContact.Columns.personId.prefix("c")
|
||||
val oId = ROrganization.Columns.oid.prefix("o")
|
||||
val pOid = RPerson.Columns.oid.prefix("p")
|
||||
|
||||
val cols = RPerson.Columns.all.map(_.prefix("p")) ++ RContact.Columns.all
|
||||
.map(_.prefix("c"))
|
||||
val cols = RPerson.Columns.all.map(_.prefix("p")) ++
|
||||
ROrganization.Columns.all.map(_.prefix("o")) ++
|
||||
RContact.Columns.all.map(_.prefix("c"))
|
||||
val from = RPerson.table ++ fr"p LEFT JOIN" ++
|
||||
ROrganization.table ++ fr"o ON" ++ pOid.is(oId) ++ fr"LEFT JOIN" ++
|
||||
RContact.table ++ fr"c ON" ++ cPers.is(pId)
|
||||
|
||||
val q = and(pColl.is(coll), pId.is(persId))
|
||||
|
||||
selectSimple(cols, from, q)
|
||||
.query[(RPerson, Option[RContact])]
|
||||
.query[(RPerson, Option[ROrganization], Option[RContact])]
|
||||
.stream
|
||||
.groupAdjacentBy(_._1)
|
||||
.map({ case (ro, chunk) =>
|
||||
val cs = chunk.toVector.flatMap(_._2)
|
||||
(ro, cs)
|
||||
.map({ case (rp, chunk) =>
|
||||
val cs = chunk.toVector.flatMap(_._3)
|
||||
val ro = chunk.map(_._2).head.flatten
|
||||
(rp, ro, cs)
|
||||
})
|
||||
.compile
|
||||
.last
|
||||
|
@ -1,6 +1,8 @@
|
||||
package docspell.store.records
|
||||
|
||||
import cats.Eq
|
||||
import cats.data.NonEmptyList
|
||||
import cats.effect._
|
||||
import fs2.Stream
|
||||
|
||||
import docspell.common.{IdRef, _}
|
||||
@ -21,7 +23,8 @@ case class RPerson(
|
||||
notes: Option[String],
|
||||
concerning: Boolean,
|
||||
created: Timestamp,
|
||||
updated: Timestamp
|
||||
updated: Timestamp,
|
||||
oid: Option[Ident]
|
||||
) {}
|
||||
|
||||
object RPerson {
|
||||
@ -42,6 +45,7 @@ object RPerson {
|
||||
val concerning = Column("concerning")
|
||||
val created = Column("created")
|
||||
val updated = Column("updated")
|
||||
val oid = Column("oid")
|
||||
val all = List(
|
||||
pid,
|
||||
cid,
|
||||
@ -53,7 +57,8 @@ object RPerson {
|
||||
notes,
|
||||
concerning,
|
||||
created,
|
||||
updated
|
||||
updated,
|
||||
oid
|
||||
)
|
||||
}
|
||||
|
||||
@ -63,7 +68,7 @@ object RPerson {
|
||||
val sql = insertRow(
|
||||
table,
|
||||
all,
|
||||
fr"${v.pid},${v.cid},${v.name},${v.street},${v.zip},${v.city},${v.country},${v.notes},${v.concerning},${v.created},${v.updated}"
|
||||
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}"
|
||||
)
|
||||
sql.update.run
|
||||
}
|
||||
@ -82,6 +87,7 @@ object RPerson {
|
||||
country.setTo(v.country),
|
||||
concerning.setTo(v.concerning),
|
||||
notes.setTo(v.notes),
|
||||
oid.setTo(v.oid),
|
||||
updated.setTo(now)
|
||||
)
|
||||
)
|
||||
@ -163,4 +169,14 @@ object RPerson {
|
||||
|
||||
def delete(personId: Ident, coll: Ident): ConnectionIO[Int] =
|
||||
deleteFrom(table, and(pid.is(personId), cid.is(coll))).update.run
|
||||
|
||||
def findOrganization(ids: Set[Ident]): ConnectionIO[Vector[PersonRef]] = {
|
||||
val cols = Seq(pid, name, oid)
|
||||
NonEmptyList.fromList(ids.toList) match {
|
||||
case Some(nel) =>
|
||||
selectSimple(cols, table, pid.isIn(nel)).query[PersonRef].to[Vector]
|
||||
case None =>
|
||||
Sync[ConnectionIO].pure(Vector.empty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,11 +8,9 @@ module Comp.CustomFieldTable exposing
|
||||
)
|
||||
|
||||
import Api.Model.CustomField exposing (CustomField)
|
||||
import Api.Model.CustomFieldList exposing (CustomFieldList)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Util.Html
|
||||
import Util.Time
|
||||
|
||||
|
||||
@ -44,7 +42,7 @@ update msg model =
|
||||
view : Model -> List CustomField -> Html Msg
|
||||
view _ items =
|
||||
div []
|
||||
[ table [ class "ui very basic center aligned table" ]
|
||||
[ table [ class "ui very basic aligned table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [ class "collapsing" ] []
|
||||
|
@ -30,6 +30,7 @@ import Api.Model.Equipment exposing (Equipment)
|
||||
import Api.Model.NewCustomField exposing (NewCustomField)
|
||||
import Api.Model.Organization exposing (Organization)
|
||||
import Api.Model.Person exposing (Person)
|
||||
import Api.Model.ReferenceList exposing (ReferenceList)
|
||||
import Api.Model.Tag exposing (Tag)
|
||||
import Comp.CustomFieldForm
|
||||
import Comp.EquipmentForm
|
||||
@ -134,7 +135,10 @@ editPerson flags persId pm =
|
||||
, loading = True
|
||||
, result = Nothing
|
||||
}
|
||||
, Api.getPersonFull persId flags GetPersonResp
|
||||
, Cmd.batch
|
||||
[ Api.getPersonFull persId flags GetPersonResp
|
||||
, Api.getOrgLight flags GetOrgsResp
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@ -150,14 +154,18 @@ editEquip flags equipId em =
|
||||
)
|
||||
|
||||
|
||||
initCorrPerson : String -> Comp.PersonForm.Model -> Model
|
||||
initCorrPerson itemId pm =
|
||||
init itemId (PMR pm)
|
||||
initCorrPerson : Flags -> String -> Comp.PersonForm.Model -> ( Model, Cmd Msg )
|
||||
initCorrPerson flags itemId pm =
|
||||
( init itemId (PMR pm)
|
||||
, Api.getOrgLight flags GetOrgsResp
|
||||
)
|
||||
|
||||
|
||||
initConcPerson : String -> Comp.PersonForm.Model -> Model
|
||||
initConcPerson itemId pm =
|
||||
init itemId (PMC pm)
|
||||
initConcPerson : Flags -> String -> Comp.PersonForm.Model -> ( Model, Cmd Msg )
|
||||
initConcPerson flags itemId pm =
|
||||
( init itemId (PMC pm)
|
||||
, Api.getOrgLight flags GetOrgsResp
|
||||
)
|
||||
|
||||
|
||||
initTag : String -> Comp.TagForm.Model -> Model
|
||||
@ -198,6 +206,7 @@ type Msg
|
||||
| GetOrgResp (Result Http.Error Organization)
|
||||
| GetPersonResp (Result Http.Error Person)
|
||||
| GetEquipResp (Result Http.Error Equipment)
|
||||
| GetOrgsResp (Result Http.Error ReferenceList)
|
||||
|
||||
|
||||
type Value
|
||||
@ -304,6 +313,43 @@ update flags msg model =
|
||||
, Nothing
|
||||
)
|
||||
|
||||
GetOrgsResp (Ok list) ->
|
||||
case model.form of
|
||||
PMC pm ->
|
||||
let
|
||||
( p_, c_ ) =
|
||||
Comp.PersonForm.update flags (Comp.PersonForm.SetOrgs list.items) pm
|
||||
in
|
||||
( { model
|
||||
| loading = False
|
||||
, form = PMC p_
|
||||
}
|
||||
, Cmd.map PersonMsg c_
|
||||
, Nothing
|
||||
)
|
||||
|
||||
PMR pm ->
|
||||
let
|
||||
( p_, c_ ) =
|
||||
Comp.PersonForm.update flags (Comp.PersonForm.SetOrgs list.items) pm
|
||||
in
|
||||
( { model
|
||||
| loading = False
|
||||
, form = PMR p_
|
||||
}
|
||||
, Cmd.map PersonMsg c_
|
||||
, Nothing
|
||||
)
|
||||
|
||||
_ ->
|
||||
( { model | loading = False }, Cmd.none, Nothing )
|
||||
|
||||
GetOrgsResp (Err err) ->
|
||||
( { model | loading = False, result = Just (BasicResult False (Util.Http.errorToString err)) }
|
||||
, Cmd.none
|
||||
, Nothing
|
||||
)
|
||||
|
||||
GetEquipResp (Ok equip) ->
|
||||
case model.form of
|
||||
EM em ->
|
||||
|
@ -10,6 +10,7 @@ module Comp.Dropdown exposing
|
||||
, makeSingleList
|
||||
, mkOption
|
||||
, notSelected
|
||||
, orgDropdown
|
||||
, setMkOption
|
||||
, update
|
||||
, view
|
||||
@ -19,6 +20,7 @@ module Comp.Dropdown exposing
|
||||
{-| This needs to be rewritten from scratch!
|
||||
-}
|
||||
|
||||
import Api.Model.IdName exposing (IdName)
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (..)
|
||||
@ -28,6 +30,17 @@ import Util.Html exposing (onKeyUp)
|
||||
import Util.List
|
||||
|
||||
|
||||
orgDropdown : Model IdName
|
||||
orgDropdown =
|
||||
makeModel
|
||||
{ multiple = False
|
||||
, searchable = \n -> n > 0
|
||||
, makeOption = \e -> { value = e.id, text = e.name, additional = "" }
|
||||
, labelColor = \_ -> \_ -> ""
|
||||
, placeholder = "Choose an organization"
|
||||
}
|
||||
|
||||
|
||||
type alias Option =
|
||||
{ value : String
|
||||
, text : String
|
||||
|
@ -47,10 +47,11 @@ update _ msg model =
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
table [ class "ui selectable table" ]
|
||||
table [ class "ui very basic aligned table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [] [ text "Name" ]
|
||||
[ th [ class "collapsing" ] []
|
||||
, th [] [ text "Name" ]
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
@ -62,9 +63,18 @@ renderEquipmentLine : Model -> Equipment -> Html Msg
|
||||
renderEquipmentLine model equip =
|
||||
tr
|
||||
[ classList [ ( "active", model.selected == Just equip ) ]
|
||||
]
|
||||
[ td [ class "collapsing" ]
|
||||
[ a
|
||||
[ href "#"
|
||||
, class "ui basic small blue label"
|
||||
, onClick (Select equip)
|
||||
]
|
||||
[ td []
|
||||
[ i [ class "edit icon" ] []
|
||||
, text "Edit"
|
||||
]
|
||||
]
|
||||
, td []
|
||||
[ text equip.name
|
||||
]
|
||||
]
|
||||
|
@ -43,15 +43,15 @@ update msg model =
|
||||
view : Model -> List FolderItem -> Html Msg
|
||||
view _ items =
|
||||
div []
|
||||
[ table [ class "ui very basic center aligned table" ]
|
||||
[ table [ class "ui very basic aligned table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [ class "collapsing" ] []
|
||||
, th [] [ text "Name" ]
|
||||
, th [] [ text "Owner" ]
|
||||
, th [] [ text "Owner or Member" ]
|
||||
, th [] [ text "#Member" ]
|
||||
, th [] [ text "Created" ]
|
||||
, th [ class "collapsing" ] [ text "Owner or Member" ]
|
||||
, th [ class "collapsing" ] [ text "#Member" ]
|
||||
, th [ class "collapsing" ] [ text "Created" ]
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
@ -79,14 +79,14 @@ viewItem item =
|
||||
, td []
|
||||
[ text item.owner.name
|
||||
]
|
||||
, td []
|
||||
, td [ class "center aligned" ]
|
||||
[ Util.Html.checkbox item.isMember
|
||||
]
|
||||
, td []
|
||||
, td [ class "center aligned" ]
|
||||
[ String.fromInt item.memberCount
|
||||
|> text
|
||||
]
|
||||
, td []
|
||||
, td [ class "center aligned" ]
|
||||
[ Util.Time.formatDateShort item.created
|
||||
|> text
|
||||
]
|
||||
|
@ -7,6 +7,7 @@ module Comp.ItemDetail.Model exposing
|
||||
, UpdateResult
|
||||
, emptyModel
|
||||
, isEditNotes
|
||||
, personMatchesOrg
|
||||
, resultModel
|
||||
, resultModelCmd
|
||||
, resultModelCmdSub
|
||||
@ -20,6 +21,7 @@ import Api.Model.FolderList exposing (FolderList)
|
||||
import Api.Model.IdName exposing (IdName)
|
||||
import Api.Model.ItemDetail exposing (ItemDetail)
|
||||
import Api.Model.ItemProposals exposing (ItemProposals)
|
||||
import Api.Model.Person exposing (Person)
|
||||
import Api.Model.PersonList exposing (PersonList)
|
||||
import Api.Model.ReferenceList exposing (ReferenceList)
|
||||
import Api.Model.SentMails exposing (SentMails)
|
||||
@ -100,6 +102,7 @@ type alias Model =
|
||||
, customFieldSavingIcon : Dict String String
|
||||
, customFieldThrottle : Throttle Msg
|
||||
, allTags : List Tag
|
||||
, allPersons : Dict String Person
|
||||
}
|
||||
|
||||
|
||||
@ -205,6 +208,7 @@ emptyModel =
|
||||
, customFieldSavingIcon = Dict.empty
|
||||
, customFieldThrottle = Throttle.create 1
|
||||
, allTags = []
|
||||
, allPersons = Dict.empty
|
||||
}
|
||||
|
||||
|
||||
@ -322,3 +326,19 @@ resultModelCmd ( model, cmd ) =
|
||||
resultModelCmdSub : ( Model, Cmd Msg, Sub Msg ) -> UpdateResult
|
||||
resultModelCmdSub ( model, cmd, sub ) =
|
||||
UpdateResult model cmd sub Comp.LinkTarget.LinkNone
|
||||
|
||||
|
||||
personMatchesOrg : Model -> Bool
|
||||
personMatchesOrg model =
|
||||
let
|
||||
org =
|
||||
Comp.Dropdown.getSelected model.corrOrgModel
|
||||
|> List.head
|
||||
|
||||
persOrg =
|
||||
Comp.Dropdown.getSelected model.corrPersonModel
|
||||
|> List.head
|
||||
|> Maybe.andThen (\idref -> Dict.get idref.id model.allPersons)
|
||||
|> Maybe.andThen .organization
|
||||
in
|
||||
org == Nothing || org == persOrg
|
||||
|
@ -252,6 +252,7 @@ update key flags inav settings msg model =
|
||||
, getOptions flags
|
||||
, proposalCmd
|
||||
, Api.getSentMails flags item.id SentMailsResp
|
||||
, Api.getPersons flags "" GetPersonResp
|
||||
, Cmd.map CustomFieldMsg (Comp.CustomFieldMultiInput.initCmd flags)
|
||||
]
|
||||
, sub =
|
||||
@ -347,12 +348,14 @@ update key flags inav settings msg model =
|
||||
( m2, c2 ) =
|
||||
Comp.Dropdown.update m model.corrOrgModel
|
||||
|
||||
newModel =
|
||||
{ model | corrOrgModel = m2 }
|
||||
|
||||
idref =
|
||||
Comp.Dropdown.getSelected m2 |> List.head
|
||||
|
||||
newModel =
|
||||
{ model
|
||||
| corrOrgModel = m2
|
||||
}
|
||||
|
||||
save =
|
||||
if isDropdownChangeMsg m then
|
||||
setCorrOrg flags newModel idref
|
||||
@ -609,11 +612,46 @@ update key flags inav settings msg model =
|
||||
( conc, corr ) =
|
||||
List.partition .concerning ps.items
|
||||
|
||||
personDict =
|
||||
List.map (\p -> ( p.id, p )) ps.items
|
||||
|> Dict.fromList
|
||||
|
||||
corrOrg =
|
||||
Comp.Dropdown.getSelected model.corrOrgModel
|
||||
|> List.head
|
||||
|
||||
personFilter =
|
||||
case corrOrg of
|
||||
Just n ->
|
||||
\p -> p.organization == Just n
|
||||
|
||||
Nothing ->
|
||||
\_ -> True
|
||||
|
||||
concRefs =
|
||||
List.map (\e -> IdName e.id e.name) conc
|
||||
|
||||
corrRefs =
|
||||
List.map (\e -> IdName e.id e.name) corr
|
||||
List.filter personFilter corr
|
||||
|> List.map (\e -> IdName e.id e.name)
|
||||
|
||||
mkPersonOption idref =
|
||||
let
|
||||
org =
|
||||
Dict.get idref.id personDict
|
||||
|> Maybe.andThen .organization
|
||||
|> Maybe.map .name
|
||||
|> Maybe.map (Util.String.ellipsis 15)
|
||||
|> Maybe.withDefault ""
|
||||
in
|
||||
Comp.Dropdown.Option idref.id idref.name org
|
||||
|
||||
model_ =
|
||||
{ model
|
||||
| corrPersonModel = Comp.Dropdown.setMkOption mkPersonOption model.corrPersonModel
|
||||
, concPersonModel = Comp.Dropdown.setMkOption mkPersonOption model.concPersonModel
|
||||
, allPersons = personDict
|
||||
}
|
||||
|
||||
res1 =
|
||||
update key
|
||||
@ -621,7 +659,7 @@ update key flags inav settings msg model =
|
||||
inav
|
||||
settings
|
||||
(CorrPersonMsg (Comp.Dropdown.SetOptions corrRefs))
|
||||
model
|
||||
model_
|
||||
|
||||
res2 =
|
||||
update key
|
||||
@ -1113,26 +1151,30 @@ update key flags inav settings msg model =
|
||||
resultModel model
|
||||
|
||||
StartCorrPersonModal ->
|
||||
resultModel
|
||||
{ model
|
||||
| modalEdit =
|
||||
Just
|
||||
(Comp.DetailEdit.initCorrPerson
|
||||
let
|
||||
( pm, pc ) =
|
||||
Comp.DetailEdit.initCorrPerson
|
||||
flags
|
||||
model.item.id
|
||||
Comp.PersonForm.emptyModel
|
||||
in
|
||||
resultModelCmd
|
||||
( { model | modalEdit = Just pm }
|
||||
, Cmd.map ModalEditMsg pc
|
||||
)
|
||||
}
|
||||
|
||||
StartConcPersonModal ->
|
||||
resultModel
|
||||
{ model
|
||||
| modalEdit =
|
||||
Just
|
||||
(Comp.DetailEdit.initConcPerson
|
||||
let
|
||||
( p, c ) =
|
||||
Comp.DetailEdit.initConcPerson
|
||||
flags
|
||||
model.item.id
|
||||
Comp.PersonForm.emptyModel
|
||||
in
|
||||
resultModelCmd
|
||||
( { model | modalEdit = Just p }
|
||||
, Cmd.map ModalEditMsg c
|
||||
)
|
||||
}
|
||||
|
||||
StartEditPersonModal pm ->
|
||||
let
|
||||
|
@ -10,14 +10,20 @@ import Comp.DetailEdit
|
||||
import Comp.Dropdown
|
||||
import Comp.Dropzone
|
||||
import Comp.ItemDetail.AttachmentTabMenu
|
||||
import Comp.ItemDetail.Model exposing (Model, Msg(..), NotesField(..), SaveNameState(..))
|
||||
import Comp.ItemDetail.Model
|
||||
exposing
|
||||
( Model
|
||||
, Msg(..)
|
||||
, NotesField(..)
|
||||
, SaveNameState(..)
|
||||
, personMatchesOrg
|
||||
)
|
||||
import Comp.ItemMail
|
||||
import Comp.KeyInput
|
||||
import Comp.LinkTarget
|
||||
import Comp.MarkdownInput
|
||||
import Comp.SentMails
|
||||
import Comp.YesNoDimmer
|
||||
import Data.CustomFieldType
|
||||
import Data.Direction
|
||||
import Data.Fields
|
||||
import Data.Icons as Icons
|
||||
@ -883,6 +889,15 @@ item visible. This message will disappear then.
|
||||
]
|
||||
, Html.map CorrPersonMsg (Comp.Dropdown.view settings model.corrPersonModel)
|
||||
, renderCorrPersonSuggestions model
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui warning message", True )
|
||||
, ( "invisible hidden", personMatchesOrg model )
|
||||
]
|
||||
]
|
||||
[ i [ class "info icon" ] []
|
||||
, text "The selected person doesn't belong to the selected organization."
|
||||
]
|
||||
]
|
||||
, optional [ Data.Fields.ConcPerson, Data.Fields.ConcEquip ] <|
|
||||
h4 [ class "ui dividing header" ]
|
||||
|
@ -16,14 +16,14 @@ import Util.Contact
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ equips : List Organization
|
||||
{ orgs : List Organization
|
||||
, selected : Maybe Organization
|
||||
}
|
||||
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ equips = []
|
||||
{ orgs = []
|
||||
, selected = Nothing
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
update _ msg model =
|
||||
case msg of
|
||||
SetOrgs list ->
|
||||
( { model | equips = list, selected = Nothing }, Cmd.none )
|
||||
( { model | orgs = list, selected = Nothing }, Cmd.none )
|
||||
|
||||
Select equip ->
|
||||
( { model | selected = Just equip }, Cmd.none )
|
||||
@ -49,16 +49,17 @@ update _ msg model =
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
table [ class "ui selectable table" ]
|
||||
table [ class "ui very basic aligned table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [ class "collapsing" ] [ text "Name" ]
|
||||
[ th [ class "collapsing" ] []
|
||||
, th [ class "collapsing" ] [ text "Name" ]
|
||||
, th [] [ text "Address" ]
|
||||
, th [] [ text "Contact" ]
|
||||
]
|
||||
]
|
||||
, tbody []
|
||||
(List.map (renderOrgLine model) model.equips)
|
||||
(List.map (renderOrgLine model) model.orgs)
|
||||
]
|
||||
|
||||
|
||||
@ -66,9 +67,18 @@ renderOrgLine : Model -> Organization -> Html Msg
|
||||
renderOrgLine model org =
|
||||
tr
|
||||
[ classList [ ( "active", model.selected == Just org ) ]
|
||||
, onClick (Select org)
|
||||
]
|
||||
[ td [ class "collapsing" ]
|
||||
[ a
|
||||
[ href "#"
|
||||
, class "ui basic small blue label"
|
||||
, onClick (Select org)
|
||||
]
|
||||
[ i [ class "edit icon" ] []
|
||||
, text "Edit"
|
||||
]
|
||||
]
|
||||
, td [ class "collapsing" ]
|
||||
[ text org.name
|
||||
]
|
||||
, td []
|
||||
|
@ -9,9 +9,11 @@ module Comp.PersonForm exposing
|
||||
, view1
|
||||
)
|
||||
|
||||
import Api.Model.IdName exposing (IdName)
|
||||
import Api.Model.Person exposing (Person)
|
||||
import Comp.AddressForm
|
||||
import Comp.ContactField
|
||||
import Comp.Dropdown
|
||||
import Data.Flags exposing (Flags)
|
||||
import Data.UiSettings exposing (UiSettings)
|
||||
import Html exposing (..)
|
||||
@ -20,23 +22,25 @@ import Html.Events exposing (onCheck, onInput)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ org : Person
|
||||
{ person : Person
|
||||
, name : String
|
||||
, addressModel : Comp.AddressForm.Model
|
||||
, contactModel : Comp.ContactField.Model
|
||||
, notes : Maybe String
|
||||
, concerning : Bool
|
||||
, orgModel : Comp.Dropdown.Model IdName
|
||||
}
|
||||
|
||||
|
||||
emptyModel : Model
|
||||
emptyModel =
|
||||
{ org = Api.Model.Person.empty
|
||||
{ person = Api.Model.Person.empty
|
||||
, name = ""
|
||||
, addressModel = Comp.AddressForm.emptyModel
|
||||
, contactModel = Comp.ContactField.emptyModel
|
||||
, notes = Nothing
|
||||
, concerning = False
|
||||
, orgModel = Comp.Dropdown.orgDropdown
|
||||
}
|
||||
|
||||
|
||||
@ -48,15 +52,20 @@ isValid model =
|
||||
getPerson : Model -> Person
|
||||
getPerson model =
|
||||
let
|
||||
o =
|
||||
model.org
|
||||
person =
|
||||
model.person
|
||||
|
||||
org =
|
||||
Comp.Dropdown.getSelected model.orgModel
|
||||
|> List.head
|
||||
in
|
||||
{ o
|
||||
{ person
|
||||
| name = model.name
|
||||
, address = Comp.AddressForm.getAddress model.addressModel
|
||||
, contacts = Comp.ContactField.getContacts model.contactModel
|
||||
, notes = model.notes
|
||||
, concerning = model.concerning
|
||||
, organization = org
|
||||
}
|
||||
|
||||
|
||||
@ -67,6 +76,8 @@ type Msg
|
||||
| ContactMsg Comp.ContactField.Msg
|
||||
| SetNotes String
|
||||
| SetConcerning Bool
|
||||
| SetOrgs (List IdName)
|
||||
| OrgDropdownMsg (Comp.Dropdown.Msg IdName)
|
||||
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
@ -79,16 +90,32 @@ update flags msg model =
|
||||
|
||||
( m2, c2 ) =
|
||||
update flags (ContactMsg (Comp.ContactField.SetItems t.contacts)) m1
|
||||
|
||||
( m3, c3 ) =
|
||||
update flags
|
||||
(OrgDropdownMsg
|
||||
(Comp.Dropdown.SetSelection
|
||||
(List.filterMap identity [ t.organization ])
|
||||
)
|
||||
)
|
||||
m2
|
||||
in
|
||||
( { m2
|
||||
| org = t
|
||||
( { m3
|
||||
| person = t
|
||||
, name = t.name
|
||||
, notes = t.notes
|
||||
, concerning = t.concerning
|
||||
}
|
||||
, Cmd.batch [ c1, c2 ]
|
||||
, Cmd.batch [ c1, c2, c3 ]
|
||||
)
|
||||
|
||||
SetOrgs orgs ->
|
||||
let
|
||||
opts =
|
||||
Comp.Dropdown.SetOptions orgs
|
||||
in
|
||||
update flags (OrgDropdownMsg opts) model
|
||||
|
||||
AddressMsg am ->
|
||||
let
|
||||
( m1, c1 ) =
|
||||
@ -121,6 +148,15 @@ update flags msg model =
|
||||
SetConcerning _ ->
|
||||
( { model | concerning = not model.concerning }, Cmd.none )
|
||||
|
||||
OrgDropdownMsg lm ->
|
||||
let
|
||||
( dm_, cmd_ ) =
|
||||
Comp.Dropdown.update lm model.orgModel
|
||||
in
|
||||
( { model | orgModel = dm_ }
|
||||
, Cmd.map OrgDropdownMsg cmd_
|
||||
)
|
||||
|
||||
|
||||
view : UiSettings -> Model -> Html Msg
|
||||
view settings model =
|
||||
@ -156,6 +192,10 @@ view1 settings compact model =
|
||||
, label [] [ text "Use for concerning person suggestion only" ]
|
||||
]
|
||||
]
|
||||
, div [ class "field" ]
|
||||
[ label [] [ text "Organization" ]
|
||||
, Html.map OrgDropdownMsg (Comp.Dropdown.view settings model.orgModel)
|
||||
]
|
||||
, h3 [ class "ui dividing header" ]
|
||||
[ text "Address"
|
||||
]
|
||||
|
@ -10,6 +10,7 @@ import Api
|
||||
import Api.Model.BasicResult exposing (BasicResult)
|
||||
import Api.Model.Person
|
||||
import Api.Model.PersonList exposing (PersonList)
|
||||
import Api.Model.ReferenceList exposing (ReferenceList)
|
||||
import Comp.PersonForm
|
||||
import Comp.PersonTable
|
||||
import Comp.YesNoDimmer
|
||||
@ -28,7 +29,7 @@ type alias Model =
|
||||
, formModel : Comp.PersonForm.Model
|
||||
, viewMode : ViewMode
|
||||
, formError : Maybe String
|
||||
, loading : Bool
|
||||
, loading : Int
|
||||
, deleteConfirm : Comp.YesNoDimmer.Model
|
||||
, query : String
|
||||
}
|
||||
@ -45,7 +46,7 @@ emptyModel =
|
||||
, formModel = Comp.PersonForm.emptyModel
|
||||
, viewMode = Table
|
||||
, formError = Nothing
|
||||
, loading = False
|
||||
, loading = 0
|
||||
, deleteConfirm = Comp.YesNoDimmer.emptyModel
|
||||
, query = ""
|
||||
}
|
||||
@ -63,6 +64,7 @@ type Msg
|
||||
| YesNoMsg Comp.YesNoDimmer.Msg
|
||||
| RequestDelete
|
||||
| SetQuery String
|
||||
| GetOrgResp (Result Http.Error ReferenceList)
|
||||
|
||||
|
||||
update : Flags -> Msg -> Model -> ( Model, Cmd Msg )
|
||||
@ -105,17 +107,35 @@ update flags msg model =
|
||||
( { model | formModel = m2 }, Cmd.map FormMsg c2 )
|
||||
|
||||
LoadPersons ->
|
||||
( { model | loading = True }, Api.getPersons flags model.query PersonResp )
|
||||
( { model | loading = model.loading + 2 }
|
||||
, Cmd.batch
|
||||
[ Api.getPersons flags model.query PersonResp
|
||||
, Api.getOrgLight flags GetOrgResp
|
||||
]
|
||||
)
|
||||
|
||||
PersonResp (Ok orgs) ->
|
||||
PersonResp (Ok persons) ->
|
||||
let
|
||||
m2 =
|
||||
{ model | viewMode = Table, loading = False }
|
||||
{ model
|
||||
| viewMode = Table
|
||||
, loading = Basics.max 0 (model.loading - 1)
|
||||
}
|
||||
in
|
||||
update flags (TableMsg (Comp.PersonTable.SetPersons orgs.items)) m2
|
||||
update flags (TableMsg (Comp.PersonTable.SetPersons persons.items)) m2
|
||||
|
||||
PersonResp (Err _) ->
|
||||
( { model | loading = False }, Cmd.none )
|
||||
( { model | loading = Basics.max 0 (model.loading - 1) }, Cmd.none )
|
||||
|
||||
GetOrgResp (Ok list) ->
|
||||
let
|
||||
m2 =
|
||||
{ model | loading = Basics.max 0 (model.loading - 1) }
|
||||
in
|
||||
update flags (FormMsg (Comp.PersonForm.SetOrgs list.items)) m2
|
||||
|
||||
GetOrgResp (Err _) ->
|
||||
( { model | loading = Basics.max 0 (model.loading - 1) }, Cmd.none )
|
||||
|
||||
SetViewMode m ->
|
||||
let
|
||||
@ -148,7 +168,9 @@ update flags msg model =
|
||||
Comp.PersonForm.isValid model.formModel
|
||||
in
|
||||
if valid then
|
||||
( { model | loading = True }, Api.postPerson flags person SubmitResp )
|
||||
( { model | loading = model.loading + 1 }
|
||||
, Api.postPerson flags person SubmitResp
|
||||
)
|
||||
|
||||
else
|
||||
( { model | formError = Just "Please correct the errors in the form." }, Cmd.none )
|
||||
@ -162,13 +184,23 @@ update flags msg model =
|
||||
( m3, c3 ) =
|
||||
update flags LoadPersons m2
|
||||
in
|
||||
( { m3 | loading = False }, Cmd.batch [ c2, c3 ] )
|
||||
( { m3 | loading = Basics.max 0 (model.loading - 1) }, Cmd.batch [ c2, c3 ] )
|
||||
|
||||
else
|
||||
( { model | formError = Just res.message, loading = False }, Cmd.none )
|
||||
( { model
|
||||
| formError = Just res.message
|
||||
, loading = Basics.max 0 (model.loading - 1)
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
SubmitResp (Err err) ->
|
||||
( { model | formError = Just (Util.Http.errorToString err), loading = False }, Cmd.none )
|
||||
( { model
|
||||
| formError = Just (Util.Http.errorToString err)
|
||||
, loading = Basics.max 0 (model.loading - 1)
|
||||
}
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
RequestDelete ->
|
||||
update flags (YesNoMsg Comp.YesNoDimmer.activate) model
|
||||
@ -198,6 +230,11 @@ update flags msg model =
|
||||
( m, Api.getPersons flags str PersonResp )
|
||||
|
||||
|
||||
isLoading : Model -> Bool
|
||||
isLoading model =
|
||||
model.loading /= 0
|
||||
|
||||
|
||||
view : UiSettings -> Model -> Html Msg
|
||||
view settings model =
|
||||
if model.viewMode == Table then
|
||||
@ -241,7 +278,7 @@ viewTable model =
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
, ( "active", isLoading model )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
@ -253,9 +290,9 @@ viewForm : UiSettings -> Model -> Html Msg
|
||||
viewForm settings model =
|
||||
let
|
||||
newPerson =
|
||||
model.formModel.org.id == ""
|
||||
model.formModel.person.id == ""
|
||||
in
|
||||
Html.form [ class "ui segment", onSubmit Submit ]
|
||||
div [ class "ui segment" ]
|
||||
[ Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm)
|
||||
, if newPerson then
|
||||
h3 [ class "ui dividing header" ]
|
||||
@ -264,10 +301,10 @@ viewForm settings model =
|
||||
|
||||
else
|
||||
h3 [ class "ui dividing header" ]
|
||||
[ text ("Edit person: " ++ model.formModel.org.name)
|
||||
[ text ("Edit person: " ++ model.formModel.person.name)
|
||||
, div [ class "sub header" ]
|
||||
[ text "Id: "
|
||||
, text model.formModel.org.id
|
||||
, text model.formModel.person.id
|
||||
]
|
||||
]
|
||||
, Html.map FormMsg (Comp.PersonForm.view settings model.formModel)
|
||||
@ -280,14 +317,25 @@ viewForm settings model =
|
||||
[ Maybe.withDefault "" model.formError |> text
|
||||
]
|
||||
, div [ class "ui horizontal divider" ] []
|
||||
, button [ class "ui primary button", type_ "submit" ]
|
||||
, button
|
||||
[ class "ui primary button"
|
||||
, onClick Submit
|
||||
]
|
||||
[ text "Submit"
|
||||
]
|
||||
, a [ class "ui secondary button", onClick (SetViewMode Table), href "" ]
|
||||
, a
|
||||
[ class "ui secondary button"
|
||||
, onClick (SetViewMode Table)
|
||||
, href ""
|
||||
]
|
||||
[ text "Cancel"
|
||||
]
|
||||
, if not newPerson then
|
||||
a [ class "ui right floated red button", href "", onClick RequestDelete ]
|
||||
a
|
||||
[ class "ui right floated red button"
|
||||
, href ""
|
||||
, onClick RequestDelete
|
||||
]
|
||||
[ text "Delete" ]
|
||||
|
||||
else
|
||||
@ -295,7 +343,7 @@ viewForm settings model =
|
||||
, div
|
||||
[ classList
|
||||
[ ( "ui dimmer", True )
|
||||
, ( "active", model.loading )
|
||||
, ( "active", isLoading model )
|
||||
]
|
||||
]
|
||||
[ div [ class "ui loader" ] []
|
||||
|
@ -49,11 +49,13 @@ update _ msg model =
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
table [ class "ui selectable table" ]
|
||||
table [ class "ui very basic aligned table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [ class "collapsing" ] [ text "Name" ]
|
||||
, th [ class "collapsing" ] [ text "Concerning" ]
|
||||
[ th [ class "collapsing" ] []
|
||||
, th [ class "collapsing center aligned" ] [ text "Concerning" ]
|
||||
, th [] [ text "Name" ]
|
||||
, th [] [ text "Organization" ]
|
||||
, th [] [ text "Address" ]
|
||||
, th [] [ text "Contact" ]
|
||||
]
|
||||
@ -67,18 +69,32 @@ renderPersonLine : Model -> Person -> Html Msg
|
||||
renderPersonLine model person =
|
||||
tr
|
||||
[ classList [ ( "active", model.selected == Just person ) ]
|
||||
, onClick (Select person)
|
||||
]
|
||||
[ td [ class "collapsing" ]
|
||||
[ text person.name
|
||||
[ a
|
||||
[ href "#"
|
||||
, class "ui basic small blue label"
|
||||
, onClick (Select person)
|
||||
]
|
||||
, td [ class "collapsing" ]
|
||||
[ i [ class "edit icon" ] []
|
||||
, text "Edit"
|
||||
]
|
||||
]
|
||||
, td [ class "center aligned" ]
|
||||
[ if person.concerning then
|
||||
i [ class "check square outline icon" ] []
|
||||
|
||||
else
|
||||
i [ class "minus square outline icon" ] []
|
||||
]
|
||||
, td []
|
||||
[ text person.name
|
||||
]
|
||||
, td []
|
||||
[ Maybe.map .name person.organization
|
||||
|> Maybe.withDefault "-"
|
||||
|> text
|
||||
]
|
||||
, td []
|
||||
[ Util.Address.toString person.address |> text
|
||||
]
|
||||
|
@ -93,13 +93,7 @@ init =
|
||||
, selected = Nothing
|
||||
}
|
||||
, orgModel =
|
||||
Comp.Dropdown.makeModel
|
||||
{ multiple = False
|
||||
, searchable = \n -> n > 0
|
||||
, makeOption = \e -> { value = e.id, text = e.name, additional = "" }
|
||||
, labelColor = \_ -> \_ -> ""
|
||||
, placeholder = "Choose an organization"
|
||||
}
|
||||
Comp.Dropdown.orgDropdown
|
||||
, corrPersonModel =
|
||||
Comp.Dropdown.makeSingle
|
||||
{ makeOption = \e -> { value = e.id, text = e.name, additional = "" }
|
||||
|
@ -47,10 +47,11 @@ update _ msg model =
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
table [ class "ui selectable table" ]
|
||||
table [ class "ui very basic aligned table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
[ th [] [ text "Name" ]
|
||||
[ th [ class "collapsing" ] []
|
||||
, th [ class "eight wide" ] [ text "Name" ]
|
||||
, th [] [ text "Category" ]
|
||||
]
|
||||
]
|
||||
@ -63,9 +64,18 @@ renderTagLine : Model -> Tag -> Html Msg
|
||||
renderTagLine model tag =
|
||||
tr
|
||||
[ classList [ ( "active", model.selected == Just tag ) ]
|
||||
]
|
||||
[ td [ class "collapsing" ]
|
||||
[ a
|
||||
[ href "#"
|
||||
, class "ui basic small blue label"
|
||||
, onClick (Select tag)
|
||||
]
|
||||
[ td []
|
||||
[ i [ class "edit icon" ] []
|
||||
, text "Edit"
|
||||
]
|
||||
]
|
||||
, td []
|
||||
[ text tag.name
|
||||
]
|
||||
, td []
|
||||
|
Loading…
x
Reference in New Issue
Block a user