diff --git a/explore/src/main/scala/explore/tabs/AsterismEditorTile.scala b/explore/src/main/scala/explore/tabs/AsterismEditorTile.scala index a7a9bb57cc..f55f8be07f 100644 --- a/explore/src/main/scala/explore/tabs/AsterismEditorTile.scala +++ b/explore/src/main/scala/explore/tabs/AsterismEditorTile.scala @@ -20,8 +20,11 @@ import explore.model.OnAsterismUpdateParams import explore.model.OnCloneParameters import explore.model.TargetEditObsInfo import explore.model.enums.TileSizeState +import explore.targeteditor.AreAdding import explore.targeteditor.AsterismEditor +import explore.targeteditor.AsterismModifier import explore.undo.UndoSetter +import explore.utils.ToastCtx import japgolly.scalajs.react.Callback import japgolly.scalajs.react.extra.router.SetRouteVia import japgolly.scalajs.react.vdom.html_<^.* @@ -36,7 +39,7 @@ import queries.schemas.odb.ObsQueries import java.time.Instant -object AsterismEditorTile: +object AsterismEditorTile extends AsterismModifier: def asterismEditorTile( userId: Option[User.Id], @@ -56,15 +59,28 @@ object AsterismEditorTile: globalPreferences: View[GlobalPreferences], readonly: Boolean, sequenceChanged: Callback = Callback.empty, + adding: View[AreAdding], backButton: Option[VdomNode] = none - )(using FetchClient[IO, ObservationDB], Logger[IO]): Tile = { + )(using FetchClient[IO, ObservationDB], Logger[IO], ToastCtx[IO]): Tile = { + + val targetAdd = + targetSelectionPopup( + "Add", + programId, + obsIds, + obsAndTargets, + adding, + onAsterismUpdate, + readonly, + ExploreStyles.AddTargetButton + ) // Save the time here. this works for the obs and target tabs // It's OK to save the viz time for executed observations, I think. val vizTimeView = vizTime.withOnMod(t => ObsQueries.updateVisualizationTime[IO](obsIds.toList, t).runAsync) val control: VdomNode = - <.div(ExploreStyles.JustifiedEndTileControl, ObsTimeEditor(vizTimeView)) + <.div(ExploreStyles.TileTitleStrip, targetAdd, ObsTimeEditor(vizTimeView)) Tile( ObsTabTilesIds.TargetId.id, diff --git a/explore/src/main/scala/explore/tabs/ObsTabTiles.scala b/explore/src/main/scala/explore/tabs/ObsTabTiles.scala index eff87559f3..294333fe3f 100644 --- a/explore/src/main/scala/explore/tabs/ObsTabTiles.scala +++ b/explore/src/main/scala/explore/tabs/ObsTabTiles.scala @@ -44,6 +44,7 @@ import explore.model.layout.* import explore.modes.SpectroscopyModesMatrix import explore.observationtree.obsEditAttachments import explore.syntax.ui.* +import explore.targeteditor.AreAdding import explore.timingwindows.TimingWindowsPanel import explore.undo.UndoSetter import japgolly.scalajs.react.* @@ -278,6 +279,7 @@ object ObsTabTiles: p.observation.model.get.observationTime ): (_, _, _, _, _, _, _, _, _, _, _, _, _, _) => vizTime => IO(vizTime.getOrElse(Instant.now())) + .useStateView(AreAdding(false)) .render: ( props, @@ -294,7 +296,8 @@ object ObsTabTiles: selectedAttachment, sequenceChanged, chartSelector, - vizTimeOrNowPot + vizTimeOrNowPot, + adding ) => import ctx.given @@ -502,7 +505,8 @@ object ObsTabTiles: props.globalPreferences, props.isDisabled, // Any target changes invalidate the sequence - sequenceChanged.set(Pot.pending) + sequenceChanged.set(Pot.pending), + adding ) // The ExploreStyles.ConstraintsTile css adds a z-index to the constraints tile react-grid wrapper diff --git a/explore/src/main/scala/explore/tabs/TargetTabContents.scala b/explore/src/main/scala/explore/tabs/TargetTabContents.scala index 2d333c1f13..2e978de98f 100644 --- a/explore/src/main/scala/explore/tabs/TargetTabContents.scala +++ b/explore/src/main/scala/explore/tabs/TargetTabContents.scala @@ -28,6 +28,7 @@ import explore.model.syntax.all.* import explore.observationtree.AsterismGroupObsList import explore.shortcuts.* import explore.shortcuts.given +import explore.targeteditor.AreAdding import explore.targets.ObservationPasteAction import explore.targets.TargetPasteAction import explore.targets.TargetSummaryTable @@ -86,7 +87,8 @@ object TargetTabContents extends TwoPanels: selectedView: View[SelectedPanel], selectedTargetIds: View[List[Target.Id]], fullScreen: View[AladinFullScreen], - resize: UseResizeDetectorReturn + resize: UseResizeDetectorReturn, + adding: View[AreAdding] ): VdomNode = { import ctx.given @@ -316,6 +318,7 @@ object TargetTabContents extends TwoPanels: title, props.globalPreferences, props.readonly, + adding = adding, backButton = backButton.some ) @@ -608,4 +611,5 @@ object TargetTabContents extends TwoPanels: .useStateView(AladinFullScreen.Normal) // Measure its size .useResizeDetector() + .useStateView(AreAdding(false)) .render(renderFn) diff --git a/explore/src/main/scala/explore/targeteditor/AsterismEditor.scala b/explore/src/main/scala/explore/targeteditor/AsterismEditor.scala index c9822c7808..746646e247 100644 --- a/explore/src/main/scala/explore/targeteditor/AsterismEditor.scala +++ b/explore/src/main/scala/explore/targeteditor/AsterismEditor.scala @@ -96,15 +96,6 @@ object AsterismEditor extends AsterismModifier: val vizTime = props.vizTime.get - val selectedTargetView: View[Option[Target.Id]] = - View( - props.focusedTargetId, - (mod, cb) => - val oldValue = props.focusedTargetId - val newValue = mod(props.focusedTargetId) - props.setTarget(newValue, SetRouteVia.HistoryPush) >> cb(oldValue, newValue) - ) - // the 'getOrElse doesn't matter. Controls will be readonly if all are executed val unexecutedObs = obsEditInfo.unExecuted.getOrElse(props.obsIds) @@ -140,7 +131,7 @@ object AsterismEditor extends AsterismModifier: unexecutedObs, obsEditInfo.asterismIds, props.obsAndTargets, - selectedTargetView, + selectedTargetView(props.focusedTargetId, props.setTarget), props.onAsterismUpdate, vizTime, props.renderInTitle, diff --git a/explore/src/main/scala/explore/targeteditor/AsterismModifier.scala b/explore/src/main/scala/explore/targeteditor/AsterismModifier.scala index 01facc2a6f..96c7ac44e7 100644 --- a/explore/src/main/scala/explore/targeteditor/AsterismModifier.scala +++ b/explore/src/main/scala/explore/targeteditor/AsterismModifier.scala @@ -19,6 +19,7 @@ import explore.targets.TargetSource import explore.undo.UndoSetter import explore.utils.ToastCtx import japgolly.scalajs.react.* +import japgolly.scalajs.react.extra.router.SetRouteVia import lucuma.core.model.Program import lucuma.core.model.Target import lucuma.react.common.Css @@ -64,6 +65,18 @@ trait AsterismModifier: case _ => IO.unit + def selectedTargetView( + focusedTargetId: Option[Target.Id], + setTarget: (Option[Target.Id], SetRouteVia) => Callback + ): View[Option[Target.Id]] = + View( + focusedTargetId, + (mod, cb) => + val oldValue = focusedTargetId + val newValue = mod(focusedTargetId) + setTarget(newValue, SetRouteVia.HistoryPush) >> cb(oldValue, newValue) + ) + def targetSelectionPopup( label: String, programId: Program.Id,