All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lucuma.ui.utils.package.scala Maven / Gradle / Ivy

// 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.utils

import cats.Monad
import cats.data.NonEmptyList
import cats.syntax.all.*
import coulomb.Quantity
import crystal.ViewF
import crystal.ViewOptF
import crystal.react.ReuseViewOptF
import crystal.react.reuse.*
import eu.timepit.refined.types.string.NonEmptyString
import japgolly.scalajs.react.vdom.html_<^.*
import lucuma.core.optics.*
import lucuma.core.util.Enumerated
import monocle.function.At.at
import monocle.function.Index.index

import java.time.ZoneId
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import scala.annotation.targetName
import scala.collection.immutable.SortedMap

def abbreviate(s: String, maxLength: Int): String =
  if (s.length > maxLength) s"${s.substring(0, maxLength)}\u2026" else s

implicit class ListOps[A](val list: List[A]) extends AnyVal {
  def modFirstWhere(find: A => Boolean, mod: A => A): List[A] =
    list.indexWhere(find) match
      case -1 => list
      case n  => (list.take(n) :+ mod(list(n))) ++ list.drop(n + 1)

  def removeFirstWhere(find: A => Boolean): List[A] =
    list.indexWhere(find) match
      case -1 => list
      case n  => list.take(n) ++ list.drop(n + 1)
}

val versionDateFormatter: DateTimeFormatter =
  DateTimeFormatter.ofPattern("yyyyMMdd").withZone(ZoneId.from(ZoneOffset.UTC))

val versionDateTimeFormatter: DateTimeFormatter =
  DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss").withZone(ZoneId.from(ZoneOffset.UTC))

extension [A, B, C, D](list: List[(A, B, C, D)])
  def unzip4: (List[A], List[B], List[C], List[D]) =
    list.foldRight((List.empty[A], List.empty[B], List.empty[C], List.empty[D]))((tuple, accum) =>
      (tuple._1 :: accum._1, tuple._2 :: accum._2, tuple._3 :: accum._3, tuple._4 :: accum._4)
    )

extension [F[_], A](listView: ViewF[F, List[A]])
  @targetName("ListView_toListOfViews")
  def toListOfViews: List[ViewF[F, A]] =
    // It's safe to "get" since we are only invoking for existing indices.
    listView.get.indices.toList.map { i =>
      val atIndex = index[List[A], Int, A](i)
      listView
        .zoom(atIndex.getOption.andThen(_.get))(atIndex.modify)
    }

extension [F[_], K, V](mapView: ViewF[F, Map[K, V]])
  @targetName("MapView_toListOfViews")
  def toListOfViews: List[(K, ViewF[F, V])] =
    // It's safe to "get" since we are only invoking for existing keys.
    mapView.get.keys.toList.map(k =>
      k -> mapView.zoom(at[Map[K, V], K, Option[V]](k)).zoom(_.get)(f => _.map(f))
    )

extension [F[_], K, V](sortedMapView: ViewF[F, SortedMap[K, V]])
  @targetName("SortedMapView_toListOfViews")
  def toListOfViews: List[(K, ViewF[F, V])] =
    // It's safe to "get" since we are only invoking for existing keys.
    sortedMapView.get.keys.toList.map(k =>
      k -> sortedMapView.zoom(at[SortedMap[K, V], K, Option[V]](k)).zoom(_.get)(f => _.map(f))
    )

given [A: Enumerated, B: Enumerated]: Enumerated[(A, B)] =
  Enumerated
    .fromNEL(NonEmptyList.fromListUnsafe((Enumerated[A].all, Enumerated[B].all).tupled))
    .withTag { case (a, b) => s"${Enumerated[A].tag(a)}, ${Enumerated[B].tag(b)} " }

// Coulomb implicits
extension [F[_], N, U](self:          ViewF[F, Quantity[N, U]])
  def stripQuantity: ViewF[F, N] = self.as(quantityIso[N, U])

extension [F[_], N, U](self: ViewOptF[F, Quantity[N, U]])
  def stripQuantity: ViewOptF[F, N] = self.as(quantityIso[N, U])

extension [F[_], N, U](self:    ReuseViewOptF[F, Quantity[N, U]])
  def stripQuantity(implicit F: Monad[F]): ReuseViewOptF[F, N] = self.as(quantityIso[N, U])

extension [A](list: List[A])
  def zipWithMappedIndex[B](f: Int => B): List[(A, B)] =
    list.zipWithIndex.map((v, i) => (v, f(i)))

given Conversion[NonEmptyString, VdomNode] with
  def apply(s: NonEmptyString): VdomNode =
    s.value




© 2015 - 2025 Weber Informatics LLC | Privacy Policy