Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate optic helpers from explore, bump prime styles #971

Merged
merged 2 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ lib_managed/
src_managed/
project/boot/
project/plugins/project/
sbt-launch.jar

# Scala-IDE specific
.scala_dependencies
Expand Down
9 changes: 5 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ lazy val kittensVersion = "3.0.0"
lazy val http4sVersion = "0.23.23"
lazy val http4sDomVersion = "0.2.10"
lazy val lucumaCoreVersion = "0.87.0"
lazy val lucumaPrimeStylesVersion = "0.2.9"
lazy val lucumaPrimeStylesVersion = "0.2.10"
lazy val lucumaReactVersion = "0.44.1"
lazy val lucumaRefinedVersion = "0.1.2"
lazy val lucumaSchemasVersion = "0.61.0"
Expand Down Expand Up @@ -123,9 +123,10 @@ lazy val tests =
.dependsOn(testkit)
.settings(
libraryDependencies ++= Seq(
"edu.gemini" %%% "lucuma-core-testkit" % lucumaCoreVersion % Test,
"org.scalameta" %%% "munit" % "0.7.29" % Test,
"org.typelevel" %%% "discipline-munit" % "1.0.9" % Test
"edu.gemini" %%% "lucuma-core-testkit" % lucumaCoreVersion % Test,
"edu.gemini" %%% "lucuma-schemas-testkit" % lucumaSchemasVersion % Test,
"org.scalameta" %%% "munit" % "0.7.29" % Test,
"org.typelevel" %%% "discipline-munit" % "1.0.9" % Test
)
)
.enablePlugins(ScalaJSPlugin, NoPublishPlugin)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
// 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 lucuma.ui.input

import eu.timepit.refined.types.numeric.NonNegInt
import lucuma.ui.input.FormatUtils._
import lucuma.ui.input.FormatUtils.*
import munit.DisciplineSuite
import org.scalacheck.Arbitrary._
import org.scalacheck.Prop._
import org.scalacheck._
import org.scalacheck.Arbitrary.*
import org.scalacheck.Prop.*
import org.scalacheck.*

final class FormatUtilsSpec extends DisciplineSuite {
final class FormatUtilsSpec extends DisciplineSuite:
val Zero = BigInt(0)
test("stripZerosPastNPlaces") {
forAll(arbitrary[BigInt], Gen.choose(0, 999999), Gen.choose(0, 9), Gen.choose(0, 9)) {
Expand All @@ -19,4 +21,3 @@ final class FormatUtilsSpec extends DisciplineSuite {
assertEquals(stripZerosPastNPlaces(s"$i.$d", n), s"$i.$keep")
}
}
}
37 changes: 37 additions & 0 deletions modules/tests/src/test/scala/lucuma/ui/optics/OpticsSuite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// 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 lucuma.ui.optics

import cats.kernel.Eq
import lucuma.core.util.arb.ArbEnumerated.given
import lucuma.schemas.model.ObservingMode.GmosSouthLongSlit
import lucuma.schemas.model.arb.ArbObservingMode.given
import monocle.law.discipline.LensTests
import munit.DisciplineSuite
import org.scalacheck.Arbitrary
import org.scalacheck.Arbitrary.*

class OpticsSuite extends DisciplineSuite:
val disjointZip2 =
disjointZip(
GmosSouthLongSlit.grating,
GmosSouthLongSlit.filter
)
val disjointZip3 =
disjointZip(
GmosSouthLongSlit.grating,
GmosSouthLongSlit.filter,
GmosSouthLongSlit.fpu
)
val disjointZip4 =
disjointZip(
GmosSouthLongSlit.grating,
GmosSouthLongSlit.filter,
GmosSouthLongSlit.fpu,
GmosSouthLongSlit.explicitRoi
)

checkAll("disjointZip2", LensTests(disjointZip2))
checkAll("disjointZip3", LensTests(disjointZip3))
checkAll("disjointZip4", LensTests(disjointZip4))
56 changes: 56 additions & 0 deletions modules/ui/src/main/scala/lucuma/ui/optics/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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 lucuma.ui.optics

import cats.syntax.all.*
import monocle.Iso
import monocle.Lens

// Lenses must be disjoint (not overlap), or the result will be unsafe.
// See https://github.com/optics-dev/Monocle/issues/545
def disjointZip[S, A, B](l1: Lens[S, A], l2: Lens[S, B]): Lens[S, (A, B)] =
Lens((s: S) => (l1.get(s), l2.get(s)))((ab: (A, B)) =>
(s: S) => l2.replace(ab._2)(l1.replace(ab._1)(s))
)

def disjointZip[S, A, B, C](l1: Lens[S, A], l2: Lens[S, B], l3: Lens[S, C]): Lens[S, (A, B, C)] =
Lens((s: S) => (l1.get(s), l2.get(s), l3.get(s)))((abc: (A, B, C)) =>
(s: S) => l3.replace(abc._3)(l2.replace(abc._2)(l1.replace(abc._1)(s)))
)

def disjointZip[S, A, B, C, D](
l1: Lens[S, A],
l2: Lens[S, B],
l3: Lens[S, C],
l4: Lens[S, D]
): Lens[S, (A, B, C, D)] =
Lens((s: S) => (l1.get(s), l2.get(s), l3.get(s), l4.get(s)))((abc: (A, B, C, D)) =>
(s: S) => l4.replace(abc._4)(l3.replace(abc._3)(l2.replace(abc._2)(l1.replace(abc._1)(s))))
)

def disjointZip[S, A, B, C, D, E](
l1: Lens[S, A],
l2: Lens[S, B],
l3: Lens[S, C],
l4: Lens[S, D],
l5: Lens[S, E]
): Lens[S, (A, B, C, D, E)] =
Lens((s: S) => (l1.get(s), l2.get(s), l3.get(s), l4.get(s), l5.get(s)))((abc: (A, B, C, D, E)) =>
(s: S) =>
l5.replace(abc._5)(
l4.replace(abc._4)(l3.replace(abc._3)(l2.replace(abc._2)(l1.replace(abc._1)(s))))
)
)

// This only behaves as a lawful lens as long as A and B are both null or both set.
def unsafeDisjointOptionZip[S, A, B](
l1: Lens[S, Option[A]],
l2: Lens[S, Option[B]]
): Lens[S, Option[(A, B)]] =
Lens((s: S) => (l1.get(s), l2.get(s)).tupled)((ab: Option[(A, B)]) =>
(s: S) => l2.replace(ab.map(_._2))(l1.replace(ab.map(_._1))(s))
)

def optionIso[A, B](iso: Iso[A, B]): Iso[Option[A], Option[B]] =
Iso[Option[A], Option[B]](_.map(iso.get))(_.map(iso.reverseGet))