by

Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Aug 07 12:59
    scala-steward opened #633
  • Aug 07 07:30
    scala-steward opened #632
  • Aug 04 09:27
    ddworak closed #624
  • Aug 04 09:27
    ddworak closed #553
  • Aug 03 17:16
    scala-steward opened #631
  • Aug 02 12:11
    GuillauG starred UdashFramework/udash-core
  • Jul 30 17:31
  • Jul 30 11:05

    ddworak on master

    Update async-http-client-backen… Merge pull request #628 from sc… (compare)

  • Jul 30 11:05
    ddworak closed #628
  • Jul 30 11:05

    ddworak on master

    Update jetty-client, jetty-rewr… Merge pull request #629 from sc… (compare)

  • Jul 30 11:05
    ddworak closed #629
  • Jul 30 11:05
    ddworak closed #630
  • Jul 30 04:45
    scala-steward opened #630
  • Jul 29 22:58
    scala-steward opened #629
  • Jul 25 06:32
    alexmarkelenkov starred UdashFramework/udash-core
  • Jul 24 10:47
    scala-steward opened #628
  • Jul 24 10:02

    ddworak on master

    Update silencer-lib, silencer-p… Merge pull request #627 from sc… (compare)

  • Jul 24 10:02
    ddworak closed #627
  • Jul 24 10:02

    ddworak on master

    Update upickle to 1.2.0 Merge pull request #626 from sc… (compare)

  • Jul 24 10:02
    ddworak closed #626
Dawid Dworak
@ddworak
nope, that's atmosphere.js missing
you're getting close!
Dawid Dworak
@ddworak
we're using 2.3.8 in your udash version I think, but it should work with anything modern enough like https://cdnjs.com/libraries/atmosphere/2.2.12
Jiuyang Liu
@sequencer
After I adding atmosphere, It said popper is not found.
which popper version should I use?
Jiuyang Liu
@sequencer
I randomly selected val popperVersion = "1.11.0", it works!
Thank you @ddworak, although without bundler it's a little ugly :p
Dawid Dworak
@ddworak
Well, you don't really need scalajs-bundler for what you did here.
I'm not sure how mill support for it works anyway
You can just use npm / webpack / your favorite web dependency technology here and call it as an external process
In general, I agree and I'd like to use bundler if I have to work with deps, but the impact on the codebase is too bad for now. A lot of times you need to manually ensure require is called and if any dependency is not modular, you basically have to do almost what you did in your HTML file but in webpack scripts
My bias might be related to the fact, that we don't really use bootstrap internally, so no js deps for us. With just jquery or nothing at all it's rarely worth to use a build system
Jiuyang Liu
@sequencer
Got it!
I'm not so familiar with webpack / npm, but I'll try to find a clean way to do so.
Patrick Refondini
@refond

Playing with udash.g8 generated project, is there a way to prevent network call for CSS resources as in :

package io.udash.bootstrap
(...)
object UdashBootstrap {
(...)
  /** Loads FontAwesome styles. */
  def loadFontAwesome(): Element = link(rel := "stylesheet", href := "https://use.fontawesome.com/releases/v5.10.1/css/all.css").render

  /** Loads Bootstrap styles. */
  def loadBootstrapStyles(): Element = link(rel := "stylesheet", href := "https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css").render
}

I would like local resources instead, to prevent firewall complications and more generaly remote resources dependencies. I naively tried:

package com.escalesoft.urock.frontend
(...)
object UdashBootstrapLocal {
(...)
  /** Loads FontAwesome styles. */
  def loadFontAwesome(): Element = link(rel := "stylesheet", href := "/styles/fontawesome_all.css").render

  /** Loads Bootstrap styles. */
  def loadBootstrapStyles(): Element = link(rel := "stylesheet", href := "/styles/bootstrap.min.css").render
}

With static fontawesome and boostrap resources in frontend/src/main/assets/styles

Is there a simple way but correct way to achieve this goal ?

Dawid Dworak
@ddworak
Your approach is almost correct, but you'd have to append those links to dom.document.body. You can also avoid the code altogether by modifying index.html.
Patrick Refondini
@refond

@ddworak I tried modifying the index.html file as :

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>urock</title>

    <script src="/scripts/frontend-deps.js"></script>
    <script src="/scripts/frontend.js"></script>

    <link rel="stylesheet" type="text/css" href="/styles/main.css">
    <link rel="stylesheet" type="text/css" href="/styles/bootstrap.min.css">
    <link rel="stylesheet" type="text/css" href="/styles/all.css">

</head>
<body>
    <div id="application"></div>
</body>
</html>

It works perfectly for bootstrap styles but breaks the font awesome styling. I am not a CSS guru by far! I'll try to find out a solution and post back.
I did not understood your "links to" dom.document.body proposal, still have to get some reading about your great framework! Thanks

youssef
@manyoussef7_twitter
how can i make UdashButton()("Test butoon")
i got error
Dawid Dworak
@ddworak

@refond
When you do link(rel := "stylesheet", href := "/styles/fontawesome_all.css").render you're only creating a the link element object in memory (as in https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement). In order for the browser to interpret the tag, it needs to be appended to the DOM document. In your example that'd be dom.document.body.appendChild(loadBootstrapStyles()).

As far as font awesome issue is concerned, as long as the stylesheet file is accessible by the browser, there's nothing Udash does about font awesome (we only wrap the classnames so you can easily access them in the code). You can debug in the browser to see why the font is not loaded / chosen.

@manyoussef7_twitter can you provide more details? Also, you can take a look at the examples in https://guide.udash.io/ext/bootstrap or even the udash g8 template, which should have a button or two ;)
youssef
@manyoussef7_twitter
@ddworak i got compilation error

val testbutton=UdashButton()("test")

error : Error:(54, 36) type mismatch; found : String("test") required: io.udash.bindings.modifiers.Binding.NestedInterceptor => scalatags.JsDom.all.Modifier (which expands to) (io.udash.bindings.modifiers.Binding => io.udash.bindings.modifiers.Binding) => scalatags.generic.Modifier[org.scalajs.dom.raw.Element] val testbuton=UdashButton()("test")

Patrick Refondini
@refond

@manyoussef7_twitter maybe:

val testButton = UdashButton()(nested => "test")

will do the trick !?

youssef
@manyoussef7_twitter

yes it does ,but for avoiding that boilerplate ,the trick is to have

import io.udash.bootstrap._

so i can write

UdashButton()("test")

Thank you

@manyoussef7
Patrick Refondini
@refond

@ddworak The fontawsome CSS does not behave as the bootstrap one because it contains relative url references to, at least, webfonts such as:

url("../webfonts/fa-solid-900.woff")

So the simple: wget https://use.fontawesome.com/releases/v5.10.1/css/all.css could not work. After downloading the full "Font Awesome Free for the Web" package containing all css sibling directories such as webfonts, js, svgs... and placing it in: in frontend/src/main/assets/staticstyles/fontawesome/
it works perfectly either by replacing:

class RootView(translationsService: TranslationsService) extends ContainerView with CssView {
(...)
 UdashBootstrap.loadBootstrapStyles(),
 UdashBootstrap.loadFontAwesome(),
(...)

by:

 link(rel := "stylesheet", href := "/staticstyles/bootstrap.min.css"),
 link(rel := "stylesheet", href := "/staticstyles/fontawesome/css/all.min.css"),

or simply adding these to frontend/src/main/assets/index.html
as :

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>urock</title>

    <script src="/scripts/frontend-deps.js"></script>
    <script src="/scripts/frontend.js"></script>

    <link rel="stylesheet" type="text/css" href="/styles/main.css">

    <link rel="stylesheet" type="text/css" href="/staticstyles/fontawesome/css/all.min.css">
    <link rel="stylesheet" type="text/css" href="/staticstyles/bootstrap.min.css">

</head>
<body>
    <div id="application"></div>
</body>
</html>

Remark: Using staticstyles folder I had to adapt the backend backend.server.ApplicationServer RewriteRegexRule to include staticstyles

Patrick Refondini
@refond
@manyoussef7_twitter nice to know about the io.udash.boostrap._ import, I was not aware of it!
Giulio Mecocci
@gm2211

Hi, I have the following structure:

case object RootState extends ContainerRoutingState(None)
case object LoginState extends FinalRoutingState(Some(RootState))
case object HomeState extends ContainerRoutingState(Some(RootState))
case object WelcomeState extends FinalRoutingState(Some(HomeState))
case object PatientsMainState extends ContainerRoutingState(Some(HomeState))
case object PatientsListState extends FinalRoutingState(Some(PatientsMainState))
case object CreateNewPatientState extends FinalRoutingState(Some(PatientsMainState))

and routing

  private val urlsByState: Map[RoutingState, String] = Map(
    LoginState -> FrontendRoutes.login,
    WelcomeState -> FrontendRoutes.welcome,
    PatientsMainState -> FrontendRoutes.Patients.base, // /patients
    PatientsListState -> FrontendRoutes.Patients.list, // /patients/list
    CreateNewPatientState -> FrontendRoutes.Patients.createNew // patients/new
  )

if I use the app to navigate to, say, the patients list state, all is well, however, if I refresh the page I get a blank page and a bunch of errors:

frontend-deps.js:1 Uncaught SyntaxError: Unexpected token '<'
new:9 Resource interpreted as Stylesheet but transferred with MIME type text/html: "http://localhost:8050/patients/styles/main.css".
frontend.js:1 Uncaught SyntaxError: Unexpected token '<'
DevTools failed to parse SourceMap: chrome-extension://cfnpidifppmenkapgihekkeednfoenal/vendor/browser-polyfill.js.map
antiphishing.js:16 Sending APH request...

Any ideas around what I may be getting wrong?

Giulio Mecocci
@gm2211
figured it out: I was missing / in index.hml
Giulio Mecocci
@gm2211

now the other issue I have is, given:

  override def handleStateAfterAuthCheck(state: PatientsMainState.type): Unit = {
    jQ(() => application.goTo(PatientsListState))
  }

within the presenter for PatientsMainState
and

goToStateButton()(Translations.Home.Menu.patients, PatientsMainState)

in my home menu

if I click on the button once, I get redirected to /patients/list, but if I click again, I go to /patients: it looks like the presenter is not getting invoked twice (probably because it's already present on the page).

I'm clearly doing something wrong with navigation (especially because if I don't use jQ(() => ...) the url will change to /patients/list, but my child view won't show up - any suggestions on where to look to debug this?

Bartłomiej Grochal
@bgrochal

Hello, @gm2211! According to the RoutingEngine#handleUrl docs, routing logic defined for states associated to unchanged URL fragments is not executed. Therefore a final view associated to the PatientsListState gets detached from the DOM on the second menu button click and the handleState method defined for a presenter associated to the PatientsMainState is not invoked. Also, you shouldn't need any jQuery callback for rendering views.

To fix current behaviour, I'd recommend applying one of the following approaches:

  1. Please consider whether your menu button should redirect to the PatientsListState rather than to thePatientsMainState. What actions do you really need to perform before choosing a destination state? Considering the handleStateAfterAuthCheckmethod name, it seems to me that you need to authenticate and/or authorize a user. If so, you might want to take a look at Udash Authorization Utils.
  2. Please consider whether keeping the PatientsMainState in your states hierarchy is justified. If you need this state not to be parameterized and only to provide a piece of GUI shared among multiple child views, a corresponding ViewFactory should most likely be a StaticViewFactory with a dummy EmptyPresenter (as it is probably for the RootState) which should not redirect when handling a state (and a desired state should be resolved earlier). On the other hand, if you need the PatientsMainState to share a model common to its child states, it should be a case class rather than a case object. Then, the updated PatientsMainState will be handled if it is not equal to a currently cached PatientsMainState (checked when resolving a common prefix of current and changed URLs after the second button click).
John Loehrer
@72squared

I've seen this question asked but no satisfactory answer to the question, how to serialize a third-party data type in a case class for the REST api. The docs explain how to do it on the RestAPI itself and that works, but I really need to serialize a type within one of my case classes.

Here's an example:

import org.joda.time.DateTime

trait EnhancedRestImplicits extends DefaultRestImplicits {
  implicit val dateTimeJsonAsRawReal: AsRawReal[JsonValue, DateTime] = AsRawReal.create(a => JsonValue(a.toString), b => DateTime.parse(b.value.toString))
}

object EnhancedRestImplicits extends EnhancedRestImplicits

case class User(name:String, createdAt:DateTime=DateTime.now())
object User extends RestDataCompanion[User]

trait UserApi {
  /** Returns newly created user */
  def createUser(name: String): Future[User]
  def getNow: Future[DateTime]
}

object UserApi extends RestApiCompanion[EnhancedRestImplicits, UserApi](EnhancedRestImplicits)

I've heard people mention something about GenCodec but the docs are not clear on this subject.

Roman Janusz
@ghik

Hi @72squared, default serialization is indeed based on GenCodec (it's possible to integrate with something else if necessary, e.g. Circe). Using RestDataCompanion causes a GenCodec to be derived for your type. Then, AsRawReal is inferred based on this GenCodec (see this diagram for more details on how these implicits interact).
However, when we're already at the case class level then we're working with just GenCodec (no AsRawReal here). Therefore, you need an instance of GenCodec[DateTime]. The best way to do this now is to create an alternative implementation of RestDataCompanion that will inject additional implicits:

abstract class EnhancedRestDataCompanion[T](implicit
  instances: MacroInstances[EnhancedRestImplicits, CodecWithStructure[T]]
) extends {
  implicit lazy val codec: GenCodec[T] = instances(EnhancedRestImplicits, this).codec
  implicit lazy val restStructure: RestStructure[T] = instances(EnhancedRestImplicits, this).structure
  implicit lazy val restSchema: RestSchema[T] = RestSchema.lazySchema(restStructure.standaloneSchema)
}

The details of the above implementation don't matter - is is almost exactly the same as RestDataCompanion except that it injects more implicits into typeclass materialization.
Then, you put a GenCodec[DateTime] into EnhancedRestImplicits:

trait EnhancedRestImplicits extends DefaultRestImplicits {
  implicit val dateTimeCodec: GenCodec[DateTime] = GenCodec.nullableSimple(i => DateTime.parse(i.readString()), (o, v) => o.writeString(v.toString))
}

Note that you no longer need an instance of AsRawReal[JsonValue, DateTime] because it will be inferred from this GenCodec.
Now you can write:

case class User(name: String, createdAt: DateTime)
object User extends EnhancedRestDataCompanion[User]

Also, I highly discourage you from using DateTime.now() (or any other impure function) as a default parameter value.

Roman Janusz
@ghik

Correction: it seems that you're not using OpenAPI generation (otherwise you would use RestOpenApiCompanion and not RestApiCompanion), therefore EnhancedRestDataCompanion can be simplified to just this:

abstract class EnhancedRestDataCompanion[T](implicit
  instances: MacroInstances[EnhancedRestImplicits,() => GenCodec[T]]
) {
  implicit lazy val codec: GenCodec[T] = instances(EnhancedRestImplicits, this).apply()
}

Otherwise you would also need to define an instance of RestSchema[DateTime]

John Loehrer
@72squared
okay, I'm getting closer. Thx for the help. Now I get: Error:(26, 30) Macro at line 28 failed: Cannot materialize com.avsystem.commons.serialization.GenCodec[udashdemo.User] because of problem with parameter createdAt: No GenCodec found for org.joda.time.DateTime case class User(name:String, createdAt: DateTime)
Roman Janusz
@ghik
Hmm that error should already be gone with the version that I proposed. I will try to reproduce
John Loehrer
@72squared
here's a demo repo I am playing with just to work out proof of concept. In case that helps: https://github.com/72squared/udashdemo
nevermind haha, I found the problem I think
yep. confirmed. Thx for the help.
It might be nice to include an example like this in the docs. Seems like one of the first things someone might try to figure out
Roman Janusz
@ghik
Sure, we should also probably add something like this EnhandedRestDataCompanion to the library
Analogous to RestApiCompanion with injectable implicits
John Loehrer
@72squared
Yeah that'd be helpful. Injecting implicit data serialization and deserialization handlers for different types as one standard way of handling things would make things so much easier.
One other quick question while I'm here ... what's the strategy for handling exception raising, where the implementation of an api raises an exception. Is there a way to capture that trace on the client side? or does it just show as a 500 coded error?
Or is it just better to make sure to trap any exceptions inside the implementation and use something like an EitherT
Roman Janusz
@ghik

By default, you're going to get a 500 along with exception message (which will be further translated into HttpErrorException by Udash REST client if you're using it). It's not possible to transfer the entire exception because exceptions can't be serialized in general. You can also throw HttpErrorException directly so that you have full control over what's in the HTTP response.

Exception handling is technically a part of serialization, so it can be completely replaced with something else. Udash REST itself is not bound to exceptions as the only error signaling mechanism. By defining appropriate implicits you can express errors in a more functional way using Either/EitherT or some other data type.. In order to do that, you need to plug into serialization of RestResponse, e.g.

implicit def eitherAsResponse[E, V](implicit
  errorAsBody: AsRawReal[HttpBody, E],
  successAsBody: AsRawReal[HttpBody, V]
): AsRawReal[RestResponse, Either[E, V]] = ???
John Loehrer
@72squared
okay thanks. cool framework.
Roman Janusz
@ghik
Thanks for the interest!
Giulio Mecocci
@gm2211
@bgrochal Thanks for the response! I thought I wanted shared ui components via the main view, but after further thought, I've flattened the hierarchy, removed the main state and added breadcrumbs instead (so I have homeState <- patientsListState, homeState <- newPatientState, but breadcrumbs make it look as if newpatient is a child of the list state even if it isn't)