diff --git a/common/src/main/scala/explore/model/reusability.scala b/common/src/main/scala/explore/model/reusability.scala index 0e2079dd85..962197c892 100644 --- a/common/src/main/scala/explore/model/reusability.scala +++ b/common/src/main/scala/explore/model/reusability.scala @@ -118,7 +118,7 @@ object reusability: given [D: Eq]: Reusability[Atom[D]] = Reusability.byEq given Reusability[ExecutionVisits] = Reusability.byEq given Reusability[ProgramUserWithRole] = Reusability.byEq - given Reusability[CoIInvitation] = Reusability.byEq + given Reusability[UserInvitation] = Reusability.byEq given Reusability[IsActive] = Reusability.byEq given Reusability[PAProperties] = Reusability.byEq given Reusability[GraphResult] = Reusability.byEq diff --git a/explore/src/clue/scala/queries/common/InvitationQueriesGQL.scala b/explore/src/clue/scala/queries/common/InvitationQueriesGQL.scala index d7a0bbbfe1..616622149d 100644 --- a/explore/src/clue/scala/queries/common/InvitationQueriesGQL.scala +++ b/explore/src/clue/scala/queries/common/InvitationQueriesGQL.scala @@ -6,24 +6,25 @@ package queries.common import clue.GraphQLOperation import clue.annotation.GraphQL import lucuma.schemas.ObservationDB -import explore.model.CoIInvitation +import explore.model.UserInvitation import explore.model.ProgramInvitation object InvitationQueriesGQL: @GraphQL trait CreateInviteMutation extends GraphQLOperation[ObservationDB]: val document: String = s""" - mutation($$programId: ProgramId!, $$recipientEmail: String!) { + mutation($$programId: ProgramId!, $$recipientEmail: String!, $$role: ProgramUserRole!) { createUserInvitation(input: { programId: $$programId, recipientEmail: $$recipientEmail, - role: COI + role: $$role }) { key invitation { id status recipientEmail + role email { status } @@ -34,7 +35,7 @@ object InvitationQueriesGQL: object Data: object CreateUserInvitation: - type Invitation = CoIInvitation + type Invitation = UserInvitation @GraphQL trait RevokeInvitationMutation extends GraphQLOperation[ObservationDB]: diff --git a/explore/src/clue/scala/queries/common/ProgramInvitationsSubquery.scala b/explore/src/clue/scala/queries/common/ProgramInvitationsSubquery.scala index 858ea2ee5f..4b15e94462 100644 --- a/explore/src/clue/scala/queries/common/ProgramInvitationsSubquery.scala +++ b/explore/src/clue/scala/queries/common/ProgramInvitationsSubquery.scala @@ -5,16 +5,17 @@ package queries.common import clue.GraphQLSubquery import clue.annotation.GraphQL -import explore.model.CoIInvitation +import explore.model.UserInvitation import lucuma.schemas.ObservationDB @GraphQL object ProgramInvitationsSubquery - extends GraphQLSubquery.Typed[ObservationDB, CoIInvitation]("CoIInvitation"): + extends GraphQLSubquery.Typed[ObservationDB, UserInvitation]("CoIInvitation"): override val subquery: String = """ { id recipientEmail + role status email { status diff --git a/explore/src/main/scala/explore/programs/ProgramDetailsTile.scala b/explore/src/main/scala/explore/programs/ProgramDetailsTile.scala index 9209781f90..c285aa79b4 100644 --- a/explore/src/main/scala/explore/programs/ProgramDetailsTile.scala +++ b/explore/src/main/scala/explore/programs/ProgramDetailsTile.scala @@ -10,7 +10,7 @@ import explore.model.Constants import explore.model.ProgramDetails import explore.model.ProgramTimes import explore.model.ProgramUserWithRole -import explore.model.enums.ProgramUserRole +import lucuma.core.enums.ProgramUserRole import japgolly.scalajs.react.* import japgolly.scalajs.react.vdom.html_<^.* import lucuma.core.model.Semester @@ -28,10 +28,10 @@ object ProgramDetailsTile: private type Props = ProgramDetailsTile val component = ScalaFnComponent[Props]: props => - val details: ProgramDetails = props.programDetails - val thesis: Boolean = details.allUsers.exists(_.thesis.exists(_ === true)) - val support: List[ProgramUserWithRole] = - details.allUsers.filter(_.role.contains_(ProgramUserRole.Support)) + val details: ProgramDetails = props.programDetails + val thesis: Boolean = details.allUsers.exists(_.thesis.exists(_ === true)) + val supportPrimary: List[ProgramUserWithRole] = + details.allUsers.filter(_.role === ProgramUserRole.SupportPrimary) <.div(ExploreStyles.ProgramDetailsTile)( <.div(ExploreStyles.ProgramDetailsInfoArea)( @@ -49,8 +49,8 @@ object ProgramDetailsTile: ), <.div(ExploreStyles.ProgramDetailsInfoArea)( // The Contact scientists are the program SUPPORT role which has been requested to be split into two (3278): "Principal Support" and "Additional Support". - FormInfo(support.map(_.nameWithEmail).mkString(", "), "Contact Scientists") - .when(support.nonEmpty) + FormInfo(supportPrimary.map(_.nameWithEmail).mkString(", "), "Contact Scientists") + .when(supportPrimary.nonEmpty) // FormInfo("", "Principal Support"), // FormInfo("", "Additional Support"), // The two Notifications flags are user-settable and determine whether the archive sends email notifications for new data and whether the ODB sends notifications for expired timing windows (3388, 3389) diff --git a/explore/src/main/scala/explore/programs/SupportUsers.scala b/explore/src/main/scala/explore/programs/SupportUsers.scala index 9472e9281e..312015e625 100644 --- a/explore/src/main/scala/explore/programs/SupportUsers.scala +++ b/explore/src/main/scala/explore/programs/SupportUsers.scala @@ -3,13 +3,15 @@ package explore.programs -import japgolly.scalajs.react.* -import japgolly.scalajs.react.vdom.html_<^.* -import lucuma.react.common.ReactFnProps +import cats.data.NonEmptySet import crystal.react.View import explore.model.ProgramUserWithRole +import explore.users.ProgramUsersTable +import japgolly.scalajs.react.* +import japgolly.scalajs.react.vdom.html_<^.* import lucuma.core.model.Program -import explore.proposal.ProgramUsersTable +import lucuma.react.common.ReactFnProps +import lucuma.core.enums.ProgramUserRole case class SupportUsers( programId: Program.Id, @@ -21,4 +23,9 @@ object SupportUsers: private type Props = SupportUsers private val component = ScalaFnComponent[Props]: props => - ProgramUsersTable(props.programId, props.users, props.readonly) + ProgramUsersTable( + props.programId, + props.users, + NonEmptySet.of(ProgramUserRole.SupportPrimary, ProgramUserRole.SupportSecondary), + props.readonly + ) diff --git a/explore/src/main/scala/explore/proposal/InviteUserPopup.scala b/explore/src/main/scala/explore/proposal/InviteUserPopup.scala index 07c93fa04b..8dced2e08c 100644 --- a/explore/src/main/scala/explore/proposal/InviteUserPopup.scala +++ b/explore/src/main/scala/explore/proposal/InviteUserPopup.scala @@ -15,11 +15,12 @@ import eu.timepit.refined.types.string.NonEmptyString import explore.Icons import explore.components.ui.ExploreStyles import explore.model.AppContext -import explore.model.CoIInvitation +import explore.model.UserInvitation import japgolly.scalajs.react.* import japgolly.scalajs.react.vdom.html_<^.* import lucuma.core.data.EmailAddress import lucuma.core.data.EmailPred +import lucuma.core.enums.ProgramUserRole import lucuma.core.model.Program import lucuma.core.validation.InputValidSplitEpi import lucuma.react.common.ReactFnProps @@ -40,12 +41,13 @@ import queries.common.InvitationQueriesGQL.CreateInviteMutation.Data case class InviteUserPopup( pid: Program.Id, - invitations: View[List[CoIInvitation]], + role: ProgramUserRole, + invitations: View[List[UserInvitation]], ref: OverlayPanelRef ) extends ReactFnProps(InviteUserPopup.component) object InviteUserPopup: - val MailValidator: InputValidSplitEpi[EmailAddress] = + private val MailValidator: InputValidSplitEpi[EmailAddress] = // Scala doesn't like type aliases with refined types? InputValidSplitEpi.refinedString[EmailPred].asInstanceOf[InputValidSplitEpi[EmailAddress]] @@ -69,8 +71,8 @@ object InviteUserPopup: viewKey: View[Option[String]] ): IO[Unit] = (createInvite.set(CreateInviteProcess.Running).to[IO] *> - CreateInviteMutation[IO].execute(pid, email.value.value)).attempt - .flatMap { + CreateInviteMutation[IO].execute(pid, email.value.value, props.role)).attempt + .flatMap: case Left(e) => Logger[IO].error(e)("Error creating invitation") *> createInvite.set(CreateInviteProcess.Error).to[IO] @@ -78,14 +80,12 @@ object InviteUserPopup: props.invitations.mod(r.createUserInvitation.invitation :: _).to[IO] *> viewKey.set(r.createUserInvitation.key.some).to[IO] *> createInvite.set(CreateInviteProcess.Done).to[IO] - } OverlayPanel( closeOnEscape = true, onHide = key.set(None) >> emailView.set(None).runAsyncAndForget )( - <.div( - PrimeStyles.Dialog, + <.div(PrimeStyles.Dialog)( <.div(PrimeStyles.DialogHeader, "Create CoI invitation"), <.div(PrimeStyles.DialogContent)( <.div(LucumaPrimeStyles.FormColumnCompact)( @@ -110,8 +110,9 @@ object InviteUserPopup: ) ), <.div(PrimeStyles.DialogFooter)( - Message(text = "Error submitting user invite, try later", - severity = Message.Severity.Error + Message( + text = "Error submitting user invite, try later", + severity = Message.Severity.Error ).when(inviteState.get === CreateInviteProcess.Error), Button( icon = Icons.Close, diff --git a/explore/src/main/scala/explore/proposal/ProgramUsers.scala b/explore/src/main/scala/explore/proposal/ProgramUsers.scala index 88ea8b6ef1..4e0ec0d62e 100644 --- a/explore/src/main/scala/explore/proposal/ProgramUsers.scala +++ b/explore/src/main/scala/explore/proposal/ProgramUsers.scala @@ -3,14 +3,17 @@ package explore.proposal +import cats.data.NonEmptySet import cats.data.NonEmptyList import cats.syntax.all.* import crystal.react.* import explore.Icons import explore.components.Tile -import explore.model.CoIInvitation import explore.model.ProgramUserWithRole import explore.model.ProposalTabTileIds +import explore.model.UserInvitation +import explore.users.ProgramUserInvitations +import explore.users.ProgramUsersTable import japgolly.scalajs.react.* import japgolly.scalajs.react.vdom.html_<^.* import lucuma.core.enums.InvitationStatus @@ -22,6 +25,7 @@ import lucuma.react.primereact.Button import lucuma.react.primereact.OverlayPanelRef import lucuma.ui.primereact.* import lucuma.ui.syntax.all.given +import lucuma.core.enums.ProgramUserRole enum CreateInviteProcess(private val tag: String) derives Enumerated: case Idle extends CreateInviteProcess("idle") @@ -36,13 +40,18 @@ case class ProgramUsers( pid: Program.Id, readOnly: Boolean, users: View[List[ProgramUserWithRole]], - invitations: View[List[CoIInvitation]], + invitations: View[List[UserInvitation]], state: View[ProgramUsersState] ) extends ReactFnProps(ProgramUsers.component) object ProgramUsers: + private type Props = ProgramUsers - def inviteControl(readOnly: Boolean, ref: OverlayPanelRef, state: View[ProgramUsersState]) = + private def inviteControl( + readOnly: Boolean, + ref: OverlayPanelRef, + state: View[ProgramUsersState] + ) = Button( severity = Button.Severity.Secondary, size = Button.Size.Small, @@ -57,7 +66,7 @@ object ProgramUsers: pid: Program.Id, readOnly: Boolean, users: View[List[ProgramUserWithRole]], - invitations: View[List[CoIInvitation]], + invitations: View[List[UserInvitation]], ref: OverlayPanelRef ) = Tile( @@ -66,12 +75,15 @@ object ProgramUsers: ProgramUsersState(CreateInviteProcess.Idle) )(ProgramUsers(pid, readOnly, users, invitations, _), (s, _) => inviteControl(readOnly, ref, s)) - private type Props = ProgramUsers - private val component = ScalaFnComponent[Props]: props => <.div( - ProgramUsersTable(props.pid, props.users, props.readOnly), + ProgramUsersTable( + props.pid, + props.users, + NonEmptySet.of(ProgramUserRole.Pi, ProgramUserRole.Coi, ProgramUserRole.CoiRO), + props.readOnly + ), React .Fragment( "Pending invitations", diff --git a/explore/src/main/scala/explore/proposal/ProposalEditor.scala b/explore/src/main/scala/explore/proposal/ProposalEditor.scala index 2bf0f3a19f..f3f9bb4e0a 100644 --- a/explore/src/main/scala/explore/proposal/ProposalEditor.scala +++ b/explore/src/main/scala/explore/proposal/ProposalEditor.scala @@ -16,18 +16,19 @@ import explore.components.TileController import explore.components.ui.* import explore.model.AppContext import explore.model.CallForProposal -import explore.model.CoIInvitation import explore.model.ExploreGridLayouts import explore.model.ProgramTimeRange import explore.model.ProgramUserWithRole import explore.model.Proposal import explore.model.ProposalAttachment import explore.model.ProposalTabTileIds +import explore.model.UserInvitation import explore.model.enums.GridLayoutSection import explore.model.layout.LayoutsMap import explore.undo.* import japgolly.scalajs.react.* import japgolly.scalajs.react.vdom.html_<^.* +import lucuma.core.enums.ProgramUserRole import lucuma.core.model.Program import lucuma.core.model.User import lucuma.react.common.ReactFnProps @@ -50,7 +51,7 @@ case class ProposalEditor( undoStacks: View[UndoStacks[IO, Proposal]], timeEstimateRange: Pot[Option[ProgramTimeRange]], users: View[List[ProgramUserWithRole]], - invitations: View[List[CoIInvitation]], + invitations: View[List[UserInvitation]], attachments: View[List[ProposalAttachment]], authToken: Option[NonEmptyString], cfps: List[CallForProposal], @@ -157,7 +158,7 @@ object ProposalEditor: ) <.div(ExploreStyles.MultiPanelTile)( - InviteUserPopup(props.programId, props.invitations, overlayRef), + InviteUserPopup(props.programId, ProgramUserRole.Coi, props.invitations, overlayRef), TileController( props.optUserId, resize.width.getOrElse(1), diff --git a/explore/src/main/scala/explore/proposal/ProgramUserInvitations.scala b/explore/src/main/scala/explore/users/ProgramUserInvitations.scala similarity index 87% rename from explore/src/main/scala/explore/proposal/ProgramUserInvitations.scala rename to explore/src/main/scala/explore/users/ProgramUserInvitations.scala index bba5d3490b..b96ad868e0 100644 --- a/explore/src/main/scala/explore/proposal/ProgramUserInvitations.scala +++ b/explore/src/main/scala/explore/users/ProgramUserInvitations.scala @@ -1,7 +1,7 @@ // Copyright (c) 2016-2023 Association of Universities for Research in Astronomy, Inc. (AURA) // For license information see LICENSE or https://opensource.org/licenses/BSD-3-Clause -package explore.proposal +package explore.users import cats.effect.IO import cats.syntax.all.* @@ -12,8 +12,8 @@ import explore.Icons import explore.components.* import explore.components.ui.ExploreStyles import explore.model.AppContext -import explore.model.CoIInvitation import explore.model.IsActive +import explore.model.UserInvitation import explore.model.reusability.given import japgolly.scalajs.react.* import japgolly.scalajs.react.vdom.html_<^.* @@ -29,7 +29,7 @@ import lucuma.ui.syntax.all.given import lucuma.ui.table.* import queries.common.InvitationQueriesGQL.* -case class ProgramUserInvitations(invitations: View[List[CoIInvitation]], readOnly: Boolean) +case class ProgramUserInvitations(invitations: View[List[UserInvitation]], readOnly: Boolean) extends ReactFnProps(ProgramUserInvitations.component) object ProgramUserInvitations: @@ -37,11 +37,11 @@ object ProgramUserInvitations: private case class TableMeta( isActive: View[IsActive], - invitations: View[List[CoIInvitation]], + invitations: View[List[UserInvitation]], readOnly: Boolean ) - private val ColDef = ColumnDef.WithTableMeta[CoIInvitation, TableMeta] + private val ColDef = ColumnDef.WithTableMeta[UserInvitation, TableMeta] private val KeyId: ColumnId = ColumnId("id") private val EmailId: ColumnId = ColumnId("email") @@ -57,13 +57,13 @@ object ProgramUserInvitations: private def column[V]( id: ColumnId, - accessor: CoIInvitation => V - ): ColumnDef.Single.WithTableMeta[CoIInvitation, V, TableMeta] = + accessor: UserInvitation => V + ): ColumnDef.Single.WithTableMeta[UserInvitation, V, TableMeta] = ColDef(id, accessor, columnNames(id)) private def columns( ctx: AppContext[IO] - ): List[ColumnDef.WithTableMeta[CoIInvitation, ?, TableMeta]] = + ): List[ColumnDef.WithTableMeta[UserInvitation, ?, TableMeta]] = import ctx.given List( @@ -73,11 +73,9 @@ object ProgramUserInvitations: EmailStatusId, _.emailStatus, "Email Status", - cell = { cell => - cell.value - .map(es => <.span(es.tag.toUpperCase).withTooltip(es.description)) - .getOrElse(<.span()) - } + cell = _.value + .map(es => <.span(es.tag.toUpperCase).withTooltip(es.description)) + .getOrElse(<.span()) ), ColDef( RevokeId, diff --git a/explore/src/main/scala/explore/proposal/ProgramUsersTable.scala b/explore/src/main/scala/explore/users/ProgramUsersTable.scala similarity index 95% rename from explore/src/main/scala/explore/proposal/ProgramUsersTable.scala rename to explore/src/main/scala/explore/users/ProgramUsersTable.scala index 03e8b649b4..6c0001dbd0 100644 --- a/explore/src/main/scala/explore/proposal/ProgramUsersTable.scala +++ b/explore/src/main/scala/explore/users/ProgramUsersTable.scala @@ -1,8 +1,9 @@ // Copyright (c) 2016-2023 Association of Universities for Research in Astronomy, Inc. (AURA) // For license information see LICENSE or https://opensource.org/licenses/BSD-3-Clause -package explore.proposal +package explore.users +import cats.data.NonEmptySet import cats.effect.IO import cats.syntax.all.* import crystal.react.* @@ -42,11 +43,13 @@ import lucuma.ui.table.* import lucuma.ui.utils.* import monocle.function.Each.* import queries.common.ProposalQueriesGQL.UnlinkUser +import lucuma.core.enums.ProgramUserRole case class ProgramUsersTable( - programId: Program.Id, - users: View[List[ProgramUserWithRole]], - readOnly: Boolean + programId: Program.Id, + users: View[List[ProgramUserWithRole]], + filterRoles: NonEmptySet[ProgramUserRole], + readOnly: Boolean ) extends ReactFnProps(ProgramUsersTable.component) object ProgramUsersTable: @@ -260,7 +263,8 @@ object ProgramUsersTable: severity = Button.Severity.Secondary, disabled = meta.readOnly || meta.isActive.get.value, onClick = unlink - ).mini.compact.unless(cell.value.get.role.isEmpty) // don't allow removing the PI + ).mini.compact + .unless(cell.value.get.role === ProgramUserRole.Pi) // don't allow removing the PI ) , size = 35.toPx @@ -274,8 +278,8 @@ object ProgramUsersTable: .useStateView(IsActive(false)) .useMemoBy((_, _, _) => ()): (_, ctx, _) => // cols _ => columns(ctx) - .useMemoBy((props, _, _, _) => props.users.reuseByValue): (p, _, _, _) => // rows - _.toListOfViews + .useMemoBy((props, _, _, _) => props.users.reuseByValue): (props, _, _, _) => // rows + _.toListOfViews.filter(row => props.filterRoles.contains_(row.get.role)) .useReactTableBy: (props, _, isActive, cols, rows) => TableOptions( cols, diff --git a/model/shared/src/main/scala/explore/model/ProgramDetails.scala b/model/shared/src/main/scala/explore/model/ProgramDetails.scala index 932e9bcc21..f64e425990 100644 --- a/model/shared/src/main/scala/explore/model/ProgramDetails.scala +++ b/model/shared/src/main/scala/explore/model/ProgramDetails.scala @@ -21,7 +21,7 @@ case class ProgramDetails( proposalStatus: ProposalStatus, pi: Option[ProgramUserWithRole], users: List[ProgramUserWithRole], - invitations: List[CoIInvitation], + invitations: List[UserInvitation], reference: Option[ProgramReference], allocations: CategoryAllocationList ) derives Eq: @@ -30,7 +30,7 @@ case class ProgramDetails( object ProgramDetails: val proposal: Lens[ProgramDetails, Option[Proposal]] = Focus[ProgramDetails](_.proposal) val proposalStatus: Lens[ProgramDetails, ProposalStatus] = Focus[ProgramDetails](_.proposalStatus) - val invitations: Lens[ProgramDetails, List[CoIInvitation]] = Focus[ProgramDetails](_.invitations) + val invitations: Lens[ProgramDetails, List[UserInvitation]] = Focus[ProgramDetails](_.invitations) val allUsers: Lens[ProgramDetails, List[ProgramUserWithRole]] = Lens[ProgramDetails, List[ProgramUserWithRole]](_.allUsers)(a => b => b.copy(pi = a.headOption, users = a.tail) @@ -47,7 +47,7 @@ object ProgramDetails: ps <- c.get[ProposalStatus]("proposalStatus") pi <- c.downField("pi").as[Option[ProgramUserWithRole]] us <- c.get[List[ProgramUserWithRole]]("users") - in <- c.get[List[CoIInvitation]]("userInvitations") + in <- c.get[List[UserInvitation]]("userInvitations") r <- c.downField("reference").downField("label").success.traverse(_.as[Option[ProgramReference]]) as <- c.downField("allocations").as[CategoryAllocationList] diff --git a/model/shared/src/main/scala/explore/model/ProgramUserWithRole.scala b/model/shared/src/main/scala/explore/model/ProgramUserWithRole.scala index 2dfdda9a70..5721f233b3 100644 --- a/model/shared/src/main/scala/explore/model/ProgramUserWithRole.scala +++ b/model/shared/src/main/scala/explore/model/ProgramUserWithRole.scala @@ -6,7 +6,7 @@ package explore.model import cats.Eq import cats.derived.* import cats.syntax.all.* -import explore.model.enums.ProgramUserRole +import lucuma.core.enums.ProgramUserRole import io.circe.Decoder import lucuma.core.enums.EducationalStatus import lucuma.core.enums.Gender @@ -19,16 +19,18 @@ import monocle.Lens case class ProgramUserWithRole( user: ProgramUser, partnerLink: Option[PartnerLink], - role: Option[ProgramUserRole], + // role: Option[ProgramUserRole], + role: ProgramUserRole, educationalStatus: Option[EducationalStatus], thesis: Option[Boolean], gender: Option[Gender] ) derives Eq: export user.{name, nameWithEmail} - lazy val roleName: String = role match - case None => "Pi" - case Some(role) => role.tag + lazy val roleName: String = role.tag + // role match + // case None => "Pi" + // case Some(role) => role.tag object ProgramUserWithRole: val user: Lens[ProgramUserWithRole, ProgramUser] = Focus[ProgramUserWithRole](_.user) @@ -49,7 +51,7 @@ object ProgramUserWithRole: for { u <- c.downField("user").as[ProgramUser] pl <- c.downField("partnerLink").as[Option[PartnerLink]] - role <- c.downField("role").as[Option[ProgramUserRole]] + role <- c.downField("role").as[ProgramUserRole] es <- c.downField("educationalStatus").as[Option[EducationalStatus]] th <- c.downField("thesis").as[Option[Boolean]] g <- c.downField("gender").as[Option[Gender]] diff --git a/model/shared/src/main/scala/explore/model/CoIInvitation.scala b/model/shared/src/main/scala/explore/model/UserInvitation.scala similarity index 78% rename from model/shared/src/main/scala/explore/model/CoIInvitation.scala rename to model/shared/src/main/scala/explore/model/UserInvitation.scala index d136c4f3a2..3b26015c48 100644 --- a/model/shared/src/main/scala/explore/model/CoIInvitation.scala +++ b/model/shared/src/main/scala/explore/model/UserInvitation.scala @@ -13,20 +13,23 @@ import io.circe.refined.* import lucuma.core.data.EmailAddress import lucuma.core.enums.EmailStatus import lucuma.core.enums.InvitationStatus +import lucuma.core.enums.ProgramUserRole import lucuma.core.util.Enumerated -case class CoIInvitation( +case class UserInvitation( id: String, email: EmailAddress, + role: ProgramUserRole, status: InvitationStatus, emailStatus: Option[EmailStatus] ) derives Eq -object CoIInvitation: - given Decoder[CoIInvitation] = c => +object UserInvitation: + given Decoder[UserInvitation] = c => for { id <- c.get[String]("id") em <- c.get[EmailAddress]("recipientEmail") + r <- c.get[ProgramUserRole]("role") s <- c.get[InvitationStatus]("status") es <- c.downField("email").downField("status").success.traverse(_.as[EmailStatus]) - } yield CoIInvitation(id, em, s, es) + } yield UserInvitation(id, em, r, s, es) diff --git a/model/shared/src/main/scala/explore/model/enums/ProgramUserRole.scala b/model/shared/src/main/scala/explore/model/enums/ProgramUserRole.scala deleted file mode 100644 index 8b5a74d682..0000000000 --- a/model/shared/src/main/scala/explore/model/enums/ProgramUserRole.scala +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2016-2023 Association of Universities for Research in Astronomy, Inc. (AURA) -// For license information see LICENSE or https://opensource.org/licenses/BSD-3-Clause - -package explore.model.enums - -import lucuma.core.util.Enumerated - -enum ProgramUserRole(val tag: String) derives Enumerated { - case Pi extends ProgramUserRole("Pi") - case Coi extends ProgramUserRole("Coi") - case Observer extends ProgramUserRole("Observer") - case Support extends ProgramUserRole("Support") -} diff --git a/project/Versions.scala b/project/Versions.scala index 930e76cf50..f6d332b381 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -26,7 +26,7 @@ object Versions { val lucumaITC = "0.22.3" val lucumaReact = "0.71.1" val lucumaRefined = "0.1.3" - val lucumaSchemas = "0.99.1" + val lucumaSchemas = "0.100.0" val lucumaOdbSchema = "0.13.1" val lucumaSSO = "0.6.24" val lucumaUI = "0.117.0"