Skip to content

Commit

Permalink
Merge pull request #1354 from gemini-hlsw/pure-visits-query
Browse files Browse the repository at this point in the history
Migrate to new schema visit query
  • Loading branch information
rpiaggio authored Oct 4, 2024
2 parents ae80e5a + 19fccf8 commit 4eb623a
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

package observe.ui.model

import cats.syntax.option.*
import crystal.Pot
import crystal.Pot.Pending
import crystal.Pot.Ready
Expand All @@ -17,7 +18,7 @@ import monocle.Lens
case class LoadedObservation private (
obsId: Observation.Id,
config: Pot[InstrumentExecutionConfig] = Pot.pending,
visits: Pot[ExecutionVisits] = Pot.pending
visits: Pot[Option[ExecutionVisits]] = Pot.pending
):
private def potFromEitherOption[A](e: Either[Throwable, Option[A]]): Pot[A] =
e.toTry.toPot.flatMap(_.toPot)
Expand All @@ -26,30 +27,32 @@ case class LoadedObservation private (
copy(config = potFromEitherOption(config))

def withVisits(visits: Either[Throwable, Option[ExecutionVisits]]): LoadedObservation =
copy(visits = potFromEitherOption(visits))
copy(visits = potFromEitherOption(visits.map(_.some)))

def addVisits(addedVisits: Either[Throwable, Option[ExecutionVisits]]): LoadedObservation =
copy(visits = visits match
case Ready(existing) =>
potFromEitherOption(addedVisits) match
case Ready(added) => Ready(existing.extendWith(added))
case Pending => visits
case error => error
case _ => potFromEitherOption(addedVisits)
potFromEitherOption(addedVisits.map(_.some)) match
case Ready(Some(added)) => Ready(existing.fold(added)(_.extendWith(added)).some)
case Ready(None) => Ready(existing)
case Pending => visits
case error => error
case _ => potFromEitherOption(addedVisits.map(_.some))
)

def reset: LoadedObservation =
copy(config = Pot.pending, visits = Pot.pending)

lazy val lastVisitId: Option[Visit.Id] =
visits.toOption.flatMap:
case ExecutionVisits.GmosNorth(_, visits) => visits.lastOption.map(_.id)
case ExecutionVisits.GmosSouth(_, visits) => visits.lastOption.map(_.id)
visits.toOption.flatten.map:
case ExecutionVisits.GmosNorth(visits) => visits.last.id
case ExecutionVisits.GmosSouth(visits) => visits.last.id

object LoadedObservation:
def apply(obsId: Observation.Id): LoadedObservation = new LoadedObservation(obsId)

val obsId: Lens[LoadedObservation, Observation.Id] = Focus[LoadedObservation](_.obsId)
val config: Lens[LoadedObservation, Pot[InstrumentExecutionConfig]] =
Focus[LoadedObservation](_.config)
val visits: Lens[LoadedObservation, Pot[ExecutionVisits]] = Focus[LoadedObservation](_.visits)
val visits: Lens[LoadedObservation, Pot[Option[ExecutionVisits]]] =
Focus[LoadedObservation](_.visits)
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import cats.syntax.all.*
import eu.timepit.refined.cats.given
import eu.timepit.refined.types.string.NonEmptyString
import io.circe.Decoder
import io.circe.HCursor
import io.circe.generic.semiauto.*
import io.circe.refined.given
import lucuma.core.enums.Instrument
Expand Down Expand Up @@ -82,7 +83,11 @@ object ObsSummary:
observingMode <- c.get[Option[ObservingMode]]("observingMode")
observationTime <- c.get[Option[Timestamp]]("observationTime")
posAngleConstraint <- c.get[PosAngleConstraint]("posAngleConstraint")
obsReference <- c.downField("reference").get[Option[ObservationReference]]("label")
obsReference <-
c.get[Option[HCursor]]("reference")
.map(_.map(_.get[Option[ObservationReference]]("label")).sequence.map(_.flatten))
.sequence
.flatten
yield ObsSummary(
id,
title,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import cats.effect.IO
import cats.syntax.all.*
import crystal.react.*
import japgolly.scalajs.react.*
import japgolly.scalajs.react.vdom.html_<^.*
import lucuma.core.enums.Breakpoint
import lucuma.core.model.Observation
import lucuma.core.model.sequence.InstrumentExecutionConfig
Expand All @@ -19,14 +18,12 @@ import lucuma.schemas.model.Dataset
import lucuma.schemas.model.ExecutionVisits
import lucuma.schemas.model.StepRecord
import lucuma.schemas.model.Visit
import lucuma.ui.DefaultErrorRender
import lucuma.ui.syntax.toast.*
import monocle.Optional
import monocle.Traversal
import observe.model.ExecutionState
import observe.model.StepProgress
import observe.model.odb.RecordedVisit
import observe.ui.ObserveStyles
import observe.ui.components.sequence.GmosNorthSequenceTable
import observe.ui.components.sequence.GmosSouthSequenceTable
import observe.ui.model.AppContext
Expand All @@ -41,7 +38,7 @@ import scala.collection.immutable.HashSet
case class ObservationSequence(
obsId: Observation.Id,
config: InstrumentExecutionConfig,
visits: View[ExecutionVisits],
visits: View[Option[ExecutionVisits]],
executionState: View[ExecutionState],
currentRecordedVisit: Option[RecordedVisit],
progress: Option[StepProgress],
Expand Down Expand Up @@ -107,36 +104,41 @@ object ObservationSequence:
.mod(set => if (set.contains(stepId)) set - stepId else set + stepId) >>
sequenceApi.setBreakpoint(obsId, stepId, value).runAsync

def datasetQaView(datasetId: Dataset.Id): ViewList[EditableQaFields] =
props.visits.zoom:
datasetWithId(datasetId).andThen(EditableQaFields.fromDataset)

val onDatasetQAChange: Dataset.Id => EditableQaFields => Callback =
datasetId =>
qaFields =>
datasetIdsInFlight.modState(_ + datasetId) >>
odbQueryApi
.updateDatasetQa(datasetId, qaFields)
.flatMap: _ =>
(datasetQaView(datasetId).set(qaFields) >>
datasetIdsInFlight.modState(_ - datasetId))
.to[IO]
.handleErrorWith: e =>
(datasetIdsInFlight.modState(_ - datasetId) >>
ctx.toast.show(
s"Error updating dataset QA state for $datasetId: ${e.getMessage}",
Message.Severity.Error,
sticky = true
)).to[IO]
.runAsync

(props.config, props.visits.get) match
case (InstrumentExecutionConfig.GmosNorth(config), ExecutionVisits.GmosNorth(_, visits)) =>
props.visits.toOptionView.map { visits =>
def datasetQaView(datasetId: Dataset.Id): ViewList[EditableQaFields] =
visits.zoom:
datasetWithId(datasetId).andThen(EditableQaFields.fromDataset)

datasetIdsInFlight.modState(_ + datasetId) >>
odbQueryApi
.updateDatasetQa(datasetId, qaFields)
.flatMap: _ =>
(datasetQaView(datasetId).set(qaFields) >>
datasetIdsInFlight.modState(_ - datasetId))
.to[IO]
.handleErrorWith: e =>
(datasetIdsInFlight.modState(_ - datasetId) >>
ctx.toast.show(
s"Error updating dataset QA state for $datasetId: ${e.getMessage}",
Message.Severity.Error,
sticky = true
)).to[IO]
.runAsync
}.orEmpty // If there are no visits, there's nothing to change.

props.config match // TODO Show visits even if sequence data is not available
case InstrumentExecutionConfig.GmosNorth(config) =>
GmosNorthSequenceTable(
props.clientMode,
props.obsId,
config,
visits,
props.visits.get
.collect:
case ExecutionVisits.GmosNorth(visits) => visits.toList
.orEmpty,
props.executionState.get,
props.currentRecordedVisit,
props.progress,
Expand All @@ -148,12 +150,15 @@ object ObservationSequence:
onDatasetQAChange,
datasetIdsInFlight.value
)
case (InstrumentExecutionConfig.GmosSouth(config), ExecutionVisits.GmosSouth(_, visits)) =>
case InstrumentExecutionConfig.GmosSouth(config) =>
GmosSouthSequenceTable(
props.clientMode,
props.obsId,
config,
visits,
props.visits.get
.collect:
case ExecutionVisits.GmosSouth(visits) => visits.toList
.orEmpty,
props.executionState.get,
props.currentRecordedVisit,
props.progress,
Expand All @@ -165,7 +170,3 @@ object ObservationSequence:
onDatasetQAChange,
datasetIdsInFlight.value
)
case _ =>
<.div(ObserveStyles.ObservationAreaError)(
DefaultErrorRender(new Exception("Sequence <-> Visits Instrument mismatch!"))
)
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ object ObservationExecutionDisplay:
props.rootModelData
.zoom(RootModelData.executionState.index(selectedObsId))

val visitsViewPot: Pot[View[ExecutionVisits]] =
val visitsViewPot: Pot[View[Option[ExecutionVisits]]] =
props.rootModelData
.zoom(RootModelData.nighttimeObservation)
.toOptionView
Expand All @@ -53,7 +53,11 @@ object ObservationExecutionDisplay:

val executionStateAndConfig: Option[
Pot[
(Observation.Id, InstrumentExecutionConfig, View[ExecutionVisits], View[ExecutionState])
(Observation.Id,
InstrumentExecutionConfig,
View[Option[ExecutionVisits]],
View[ExecutionState]
)
]
] =
rootModelData.nighttimeObservation.map: lo =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ case class ODBQueryApiImpl(nighttimeObservation: ViewF[IO, Option[LoadedObservat
) extends ODBQueryApi[IO]:

private def lastVisitId(lo: LoadedObservation): Option[Visit.Id] =
lo.visits.toOption.flatMap:
case ExecutionVisits.GmosNorth(_, visits) => visits.lastOption.map(_.id)
case ExecutionVisits.GmosSouth(_, visits) => visits.lastOption.map(_.id)
lo.visits.toOption.flatten.map:
case ExecutionVisits.GmosNorth(visits) => visits.last.id
case ExecutionVisits.GmosSouth(visits) => visits.last.id

override def refreshNighttimeVisits: IO[Unit] =
nighttimeObservation.toOptionView.fold(
Logger[IO].error("refreshNighttimeVisits with undefined loaded observation")
): loadedObs =>
VisitQueriesGQL
.ObservationVisits[IO]
.query(loadedObs.get.obsId, lastVisitId(loadedObs.get).orIgnore)(ErrorPolicy.IgnoreOnData)
.query(loadedObs.get.obsId, lastVisitId(loadedObs.get).orIgnore)
.map(_.observation.flatMap(_.execution))
.attempt
.flatMap: visits =>
Expand Down
2 changes: 1 addition & 1 deletion project/Settings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ object Settings {
// Gemini Libraries
val lucumaCore = "0.104.0"
val lucumaUI = "0.117.0"
val lucumaSchemas = "0.99.1"
val lucumaSchemas = "0.102.0"
val lucumaSSO = "0.6.23"
val lucumaODBSchema = "0.13.0"

Expand Down

0 comments on commit 4eb623a

Please sign in to comment.