diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d9958c50a..f42b70650 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -112,7 +112,7 @@ jobs: env: PGP_SECRET: ${{ secrets.PGP_SECRET }} PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} - run: echo $PGP_SECRET | base64 -di | gpg --import + run: echo $PGP_SECRET | base64 -d -i - | gpg --import - name: Import signing key and strip passphrase if: env.PGP_SECRET != '' && env.PGP_PASSPHRASE != '' @@ -120,7 +120,7 @@ jobs: PGP_SECRET: ${{ secrets.PGP_SECRET }} PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} run: | - echo "$PGP_SECRET" | base64 -di > /tmp/signing-key.gpg + echo "$PGP_SECRET" | base64 -d -i - > /tmp/signing-key.gpg echo "$PGP_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --import /tmp/signing-key.gpg (echo "$PGP_PASSPHRASE"; echo; echo) | gpg --command-fd 0 --pinentry-mode loopback --change-passphrase $(gpg --list-secret-keys --with-colons 2> /dev/null | grep '^sec:' | cut --delimiter ':' --fields 5 | tail -n 1) diff --git a/.gitignore b/.gitignore index c165df202..7e3fde455 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ lib_managed/ src_managed/ project/boot/ project/plugins/project/ +sbt-launch.jar # Scala-IDE specific .scala_dependencies diff --git a/.scalafmt-common.conf b/.scalafmt-common.conf index 626594604..3cb97af14 100644 --- a/.scalafmt-common.conf +++ b/.scalafmt-common.conf @@ -4,10 +4,11 @@ # this file by hand! Instead, if you wish to make changes, you should # make a PR to sbt-lucuma. -version = "3.7.12" +version = "3.7.14" style = default runner.dialect = scala3 +runner.optimizer.maxVisitsPerToken = 20000 # Avoids SearchStateExploded exceptions maxColumn = 100 project.git = true diff --git a/.scalafmt.conf b/.scalafmt.conf index 1d2d116b3..4864a8308 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,3 +1,3 @@ -version = "3.7.14" +version = "3.7.15" include ".scalafmt-common.conf" runner.dialect = scala3 diff --git a/build.sbt b/build.sbt index a83e86b77..5727c2e3b 100644 --- a/build.sbt +++ b/build.sbt @@ -8,16 +8,16 @@ lazy val reactJS = "17.0.2" lazy val catsVersion = "2.10.0" lazy val catsRetryVersion = "3.1.0" lazy val circeVersion = "0.14.6" -lazy val crystalVersion = "0.34.6" +lazy val crystalVersion = "0.35.0" lazy val fs2DomVersion = "0.3.0-M1" -lazy val kittensVersion = "3.0.0" +lazy val kittensVersion = "3.1.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 lucumaReactVersion = "0.46.0" +lazy val lucumaCoreVersion = "0.88.0" +lazy val lucumaPrimeStylesVersion = "0.2.10" +lazy val lucumaReactVersion = "0.47.0" lazy val lucumaRefinedVersion = "0.1.2" -lazy val lucumaSchemasVersion = "0.61.0" +lazy val lucumaSchemasVersion = "0.63.0" lazy val lucumaSsoVersion = "0.6.8" lazy val monocleVersion = "3.2.0" lazy val mouseVersion = "1.2.1" @@ -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) diff --git a/flake.lock b/flake.lock index da6ce7437..f60b5e27f 100644 --- a/flake.lock +++ b/flake.lock @@ -6,11 +6,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1695973661, - "narHash": "sha256-BP2H4c42GThPIhERtTpV1yCtwQHYHEKdRu7pjrmQAwo=", + "lastModified": 1698410321, + "narHash": "sha256-MphuSlgpmKwtJncGMohryHiK55J1n6WzVQ/OAfmfoMc=", "owner": "numtide", "repo": "devshell", - "rev": "cd4e2fda3150dd2f689caeac07b7f47df5197c31", + "rev": "1aed986e3c81a4f6698e85a7452cbfcc4b31a36e", "type": "github" }, "original": { @@ -55,11 +55,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1696725822, - "narHash": "sha256-B7uAOS7TkLlOg1aX01rQlYbydcyB6ZnLJSfaYbKVww8=", + "lastModified": 1698553279, + "narHash": "sha256-T/9P8yBSLcqo/v+FTOBK+0rjzjPMctVymZydbvR/Fak=", "owner": "nixos", "repo": "nixpkgs", - "rev": "5aabb5780a11c500981993d49ee93cfa6df9307b", + "rev": "90e85bc7c1a6fc0760a94ace129d3a1c61c3d035", "type": "github" }, "original": { @@ -119,11 +119,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1696872169, - "narHash": "sha256-gR/ECICEWll2PwT/pUWhiViwN2VN5fWihlKmDNidR2U=", + "lastModified": 1698638641, + "narHash": "sha256-piIhN6bnCGd3yVB4M17SOX/Ej9zq4Q4+KzzWZRRPaVs=", "owner": "typelevel", "repo": "typelevel-nix", - "rev": "6d5aa0fe626b2b8f899660caeb1a288fe4112213", + "rev": "5c281f550dcb73eafe7341767d384bcdc3ec14fd", "type": "github" }, "original": { diff --git a/modules/tests/src/test/scala/lucuma/ui/input/FormatUtilsSpec.scala b/modules/tests/src/test/scala/lucuma/ui/input/FormatUtilsSpec.scala index 26f5aed13..89c1fab02 100644 --- a/modules/tests/src/test/scala/lucuma/ui/input/FormatUtilsSpec.scala +++ b/modules/tests/src/test/scala/lucuma/ui/input/FormatUtilsSpec.scala @@ -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)) { @@ -19,4 +21,3 @@ final class FormatUtilsSpec extends DisciplineSuite { assertEquals(stripZerosPastNPlaces(s"$i.$d", n), s"$i.$keep") } } -} diff --git a/modules/tests/src/test/scala/lucuma/ui/optics/OpticsSuite.scala b/modules/tests/src/test/scala/lucuma/ui/optics/OpticsSuite.scala new file mode 100644 index 000000000..270cd31f0 --- /dev/null +++ b/modules/tests/src/test/scala/lucuma/ui/optics/OpticsSuite.scala @@ -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)) diff --git a/modules/ui/src/main/scala/lucuma/ui/components/SolarProgress.scala b/modules/ui/src/main/scala/lucuma/ui/components/SolarProgress.scala index 89fb707dd..05b643989 100644 --- a/modules/ui/src/main/scala/lucuma/ui/components/SolarProgress.scala +++ b/modules/ui/src/main/scala/lucuma/ui/components/SolarProgress.scala @@ -19,7 +19,7 @@ object SolarProgress { p.css, <.div( ^.cls := "mars-orbit orbit", - <.div(^.cls := "planet mars"), + <.div(^.cls := "planet mars"), <.div( ^.cls := "earth-orbit orbit", <.div(^.cls := "planet earth"), diff --git a/modules/ui/src/main/scala/lucuma/ui/optics/package.scala b/modules/ui/src/main/scala/lucuma/ui/optics/package.scala new file mode 100644 index 000000000..705b3aabb --- /dev/null +++ b/modules/ui/src/main/scala/lucuma/ui/optics/package.scala @@ -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)) diff --git a/project/build.properties b/project/build.properties index 27430827b..e8a1e246e 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.9.6 +sbt.version=1.9.7 diff --git a/project/plugins.sbt b/project/plugins.sbt index a753cf580..0d960ce9f 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,4 @@ addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.21.1") -val sbtLucumaVersion = "0.11.8" +val sbtLucumaVersion = "0.11.9" addSbtPlugin("edu.gemini" % "sbt-lucuma-lib" % sbtLucumaVersion) addSbtPlugin("edu.gemini" % "sbt-lucuma-css" % sbtLucumaVersion)