From 74be0497404b8175abe3ee0a354c147a3b02d1ac Mon Sep 17 00:00:00 2001 From: Carlos Quiroz Date: Mon, 9 Sep 2024 15:50:54 -0300 Subject: [PATCH] wiup --- .../explore/model/ObsConfiguration.scala | 5 ++- .../queries/common/ObservationSubquery.scala | 1 + .../queries/common/TargetQueriesGQL.scala | 33 ++++++++++-------- .../main/scala/explore/tabs/ObsTabTiles.scala | 6 +++- .../explore/tabs/TargetTabContents.scala | 4 ++- .../explore/targeteditor/AladinCell.scala | 34 ++++++++++++++++--- .../targeteditor/SiderealTargetEditor.scala | 2 ++ .../queries/schemas/odb/ObsQueries.scala | 11 ++++++ .../scala/explore/model/Observation.scala | 6 ++++ 9 files changed, 81 insertions(+), 21 deletions(-) diff --git a/common/src/main/scala/explore/model/ObsConfiguration.scala b/common/src/main/scala/explore/model/ObsConfiguration.scala index c7f07ef74d..d6a95c6b4d 100644 --- a/common/src/main/scala/explore/model/ObsConfiguration.scala +++ b/common/src/main/scala/explore/model/ObsConfiguration.scala @@ -19,6 +19,8 @@ import lucuma.schemas.model.BasicConfiguration import org.typelevel.cats.time.instances.duration.* import java.time.Duration +import eu.timepit.refined.types.string.NonEmptyString +import eu.timepit.refined.cats.* case class ObsConfiguration( configuration: Option[BasicConfiguration], @@ -29,7 +31,8 @@ case class ObsConfiguration( acquisitionOffsets: Option[NonEmptyList[Offset]], averagePA: Option[AveragePABasis], obsDuration: Option[Duration], - needGuideStar: Boolean + needGuideStar: Boolean, + selectedGSName: Option[NonEmptyString] ) derives Eq: // In case there is no guide star we still want to have a posAngle equivalent // To draw visualization diff --git a/explore/src/clue/scala/queries/common/ObservationSubquery.scala b/explore/src/clue/scala/queries/common/ObservationSubquery.scala index 9fae32c924..383c39db33 100644 --- a/explore/src/clue/scala/queries/common/ObservationSubquery.scala +++ b/explore/src/clue/scala/queries/common/ObservationSubquery.scala @@ -26,6 +26,7 @@ object ObservationSubquery extends GraphQLSubquery.Typed[ObservationDB, Observat asterism { id } + guideTargetName } constraintSet $ConstraintSetSubquery timingWindows $TimingWindowSubquery diff --git a/explore/src/clue/scala/queries/common/TargetQueriesGQL.scala b/explore/src/clue/scala/queries/common/TargetQueriesGQL.scala index 14d5b9c1c3..deab64a354 100644 --- a/explore/src/clue/scala/queries/common/TargetQueriesGQL.scala +++ b/explore/src/clue/scala/queries/common/TargetQueriesGQL.scala @@ -9,10 +9,10 @@ import lucuma.schemas.ObservationDB import lucuma.schemas.odb.* // gql: import lucuma.schemas.decoders.given -object TargetQueriesGQL { +object TargetQueriesGQL: @GraphQL - trait TargetNameQuery extends GraphQLOperation[ObservationDB] { + trait TargetNameQuery extends GraphQLOperation[ObservationDB]: // FIXME Change this to an actual name pattern query when it's available in the API val document = s""" query($$programId: ProgramId!) { @@ -23,10 +23,9 @@ object TargetQueriesGQL { } } """ - } @GraphQL - trait CreateTargetMutation extends GraphQLOperation[ObservationDB] { + trait CreateTargetMutation extends GraphQLOperation[ObservationDB]: val document = """ mutation($input: CreateTargetInput!) { createTarget(input: $input) { @@ -36,10 +35,9 @@ object TargetQueriesGQL { } } """ - } @GraphQL - trait UpdateTargetsMutation extends GraphQLOperation[ObservationDB] { + trait UpdateTargetsMutation extends GraphQLOperation[ObservationDB]: val document = """ mutation($input: UpdateTargetsInput!) { updateTargets(input: $input) { @@ -49,10 +47,9 @@ object TargetQueriesGQL { } } """ - } @GraphQL - trait CloneTargetMutation extends GraphQLOperation[ObservationDB] { + trait CloneTargetMutation extends GraphQLOperation[ObservationDB]: val document = s""" mutation($$input: CloneTargetInput!) { cloneTarget(input: $$input) { @@ -60,10 +57,21 @@ object TargetQueriesGQL { } } """ - } @GraphQL - trait TargetEditSubscription extends GraphQLOperation[ObservationDB] { + trait SetGuideTargetName extends GraphQLOperation[ObservationDB]: + val document = s""" + mutation($$input: SetGuideTargetNameInput!) { + setGuideTargetName(input: $$input) { + observation { + id + } + } + } + """ + + @GraphQL + trait TargetEditSubscription extends GraphQLOperation[ObservationDB]: val document = """ subscription($targetId: TargetId!) { targetEdit(input: {targetId: $targetId}) { @@ -71,10 +79,9 @@ object TargetQueriesGQL { } } """ - } @GraphQL - trait ProgramTargetsDelta extends GraphQLOperation[ObservationDB] { + trait ProgramTargetsDelta extends GraphQLOperation[ObservationDB]: val document = s""" subscription($$input: TargetEditInput!) { targetEdit(input: $$input) { @@ -85,5 +92,3 @@ object TargetQueriesGQL { } } """ - } -} diff --git a/explore/src/main/scala/explore/tabs/ObsTabTiles.scala b/explore/src/main/scala/explore/tabs/ObsTabTiles.scala index 5c193841fe..b12e6e3ede 100644 --- a/explore/src/main/scala/explore/tabs/ObsTabTiles.scala +++ b/explore/src/main/scala/explore/tabs/ObsTabTiles.scala @@ -263,6 +263,9 @@ object ObsTabTiles: val vizDurationView: View[Option[TimeSpan]] = props.observation.model.zoom(Observation.observationDuration) + val selectedGSNameView: View[Option[NonEmptyString]] = + props.observation.model.zoom(Observation.selectedGSName) + val asterismAsNel: Option[NonEmptyList[TargetWithId]] = NonEmptyList.fromList: props.observation.get.scienceTargetIds.toList @@ -389,7 +392,8 @@ object ObsTabTiles: sequenceOffsets.toOption.flatMap(_.acquisition), averagePA, obsDuration.map(_.toDuration), - props.observation.get.needsAGS + props.observation.get.needsAGS, + selectedGSNameView.get ) def getObsInfo(obsId: Observation.Id)(targetId: Target.Id): TargetEditObsInfo = diff --git a/explore/src/main/scala/explore/tabs/TargetTabContents.scala b/explore/src/main/scala/explore/tabs/TargetTabContents.scala index d2e3aed663..57a03097b6 100644 --- a/explore/src/main/scala/explore/tabs/TargetTabContents.scala +++ b/explore/src/main/scala/explore/tabs/TargetTabContents.scala @@ -406,6 +406,7 @@ object TargetTabContents extends TwoPanels: _, _, _, + _, const, _, _, @@ -522,7 +523,8 @@ object TargetTabContents extends TwoPanels: none, none, none, - needsAGS + needsAGS, + none ), none, props.focused.target, diff --git a/explore/src/main/scala/explore/targeteditor/AladinCell.scala b/explore/src/main/scala/explore/targeteditor/AladinCell.scala index 140d6f2233..cf18479cc6 100644 --- a/explore/src/main/scala/explore/targeteditor/AladinCell.scala +++ b/explore/src/main/scala/explore/targeteditor/AladinCell.scala @@ -52,13 +52,17 @@ import lucuma.ui.syntax.all.given import monocle.Lens import org.typelevel.log4cats.Logger import queries.schemas.UserPreferencesDB +import queries.schemas.odb.ObsQueries import java.time.Duration import java.time.Instant import scala.concurrent.duration.* +import eu.timepit.refined.types.string.NonEmptyString +import eu.timepit.refined.cats.* case class AladinCell( uid: User.Id, + obsId: Option[Observation.Id], asterism: Asterism, vizTime: Instant, obsConf: Option[ObsConfiguration], @@ -106,6 +110,9 @@ case class AladinCell( def modeSelected: Boolean = obsConf.exists(_.configuration.isDefined) + def selectedGSName: Option[NonEmptyString] = + obsConf.flatMap(_.selectedGSName) + def sciencePositionsAt(vizTime: Instant): List[Coordinates] = asterism.asList .flatMap(_.toSidereal) @@ -286,6 +293,20 @@ object AladinCell extends ModelOptics with AladinCommon: } yield () ) .useStateView(ManualAgsOverride(false)) + // Reset offset and gs if asterism change + .useEffectWithDepsBy((p, _, _, gsc, _, _, index, _, _) => + (p.selectedGSName, gsc, index.reuseByValue) + )((p, _, _, gsc, _, _, _, _, _) => + _ => + val f = gsc.value.value.flatMap(_.find(a => p.selectedGSName.exists(_ === a.name))) + Callback.log(s"From odb ${p.selectedGSName}") *> + Callback.log(gsc.value.value.foldMap(_.size)) *> + Callback.log(p.selectedGSName.map(_.value).toString) *> Callback.log( + s"Found $f" + // gsc.value.value.foldMap(_.map(_.name.value).toString) + // gsc.value.map(_.map(_.map(_.name.value)).toString) + ) + ) // Reset selection if pos angle changes except for manual selection changes .useEffectWithDepsBy((p, _, _, _, _, _, _, _, _) => p.obsConf.flatMap(_.posAngleConstraint))( (_, _, _, _, _, _, selectedIndex, _, agsOverride) => @@ -316,6 +337,7 @@ object AladinCell extends ModelOptics with AladinCommon: candidates ) if props.needsAGS => import ctx.given + println(s"GS odb ${props.selectedGSName}") val runAgs = (positions, tracking.at(vizTime), @@ -403,10 +425,14 @@ object AladinCell extends ModelOptics with AladinCommon: idx .map(agsResults.value.lift) .map(a => - flipAngle(props, agsManualOverride)(a) *> props.obsConf - .flatMap(_.selectedGS) - .map(_.set(a)) - .getOrEmpty + flipAngle(props, agsManualOverride)(a) *> + props.obsConf + .flatMap(_.selectedGS) + .map(_.set(a)) + .getOrEmpty *> + (props.obsId, a.map(_.target.name)) + .mapN((id, n) => ObsQueries.setGuideTargetName[IO](id, n).runAsyncAndForget) + .getOrEmpty ) .getOrEmpty ) diff --git a/explore/src/main/scala/explore/targeteditor/SiderealTargetEditor.scala b/explore/src/main/scala/explore/targeteditor/SiderealTargetEditor.scala index 22252fbcd6..77d6ff34be 100644 --- a/explore/src/main/scala/explore/targeteditor/SiderealTargetEditor.scala +++ b/explore/src/main/scala/explore/targeteditor/SiderealTargetEditor.scala @@ -311,12 +311,14 @@ object SiderealTargetEditor: _ === props.asterism.focus.id ) || cloning.get || props.readonly || props.obsInfo.isReadonly + val oid = props.obsInfo.current.map(_.head) React.Fragment( TargetCloneSelector(props.obsInfo, obsToCloneTo), <.div(ExploreStyles.TargetGrid)( vizTime.renderPot(vt => AladinCell( props.userId, + oid, props.asterism, vt, props.obsConf, diff --git a/explore/src/main/scala/queries/schemas/odb/ObsQueries.scala b/explore/src/main/scala/queries/schemas/odb/ObsQueries.scala index 51d614242a..622a38ef04 100644 --- a/explore/src/main/scala/queries/schemas/odb/ObsQueries.scala +++ b/explore/src/main/scala/queries/schemas/odb/ObsQueries.scala @@ -29,6 +29,7 @@ import lucuma.schemas.ObservationDB.Enums.* import lucuma.schemas.ObservationDB.Types.* import lucuma.schemas.odb.input.* import queries.common.ObsQueriesGQL.* +import queries.common.TargetQueriesGQL.SetGuideTargetName import java.time.Instant import scala.collection.immutable.SortedMap @@ -269,3 +270,13 @@ object ObsQueries: ) ) UpdateObservationMutation[F].execute(input).void + + def setGuideTargetName[F[_]: Async]( + obsId: Observation.Id, + targetName: NonEmptyString + )(using FetchClient[F, ObservationDB]) = + val input = SetGuideTargetNameInput( + observationId = obsId.assign, + targetName = targetName.assign + ) + SetGuideTargetName[F].execute(input).void diff --git a/model/shared/src/main/scala/explore/model/Observation.scala b/model/shared/src/main/scala/explore/model/Observation.scala index 5f7f96d8d2..e8d7f87a62 100644 --- a/model/shared/src/main/scala/explore/model/Observation.scala +++ b/model/shared/src/main/scala/explore/model/Observation.scala @@ -53,6 +53,7 @@ case class Observation( status: ObsStatus, activeStatus: ObsActiveStatus, scienceTargetIds: AsterismIds, + selectedGSName: Option[NonEmptyString], constraints: ConstraintSet, timingWindows: List[TimingWindow], attachmentIds: SortedSet[ObsAttachment.Id], @@ -204,6 +205,7 @@ object Observation: val validations = Focus[Observation](_.validations) val observerNotes = Focus[Observation](_.observerNotes) val calibrationRole = Focus[Observation](_.calibrationRole) + val selectedGSName = Focus[Observation](_.selectedGSName) private case class TargetIdWrapper(id: Target.Id) private object TargetIdWrapper: @@ -221,6 +223,9 @@ object Observation: status <- c.get[ObsStatus]("status") activeStatus <- c.get[ObsActiveStatus]("activeStatus") scienceTargetIds <- c.downField("targetEnvironment").get[List[TargetIdWrapper]]("asterism") + selectedGSName <- c.downField("targetEnvironment") + .downField("guideTargetName") + .as[Option[NonEmptyString]] constraints <- c.get[ConstraintSet]("constraintSet") timingWindows <- c.get[List[TimingWindow]]("timingWindows") attachmentIds <- c.get[List[AttachmentIdWrapper]]("obsAttachments") @@ -244,6 +249,7 @@ object Observation: status, activeStatus, SortedSet.from(scienceTargetIds.map(_.id)), + selectedGSName, constraints, timingWindows, SortedSet.from(attachmentIds.map(_.id)),