Giter VIP home page Giter VIP logo

Comments (11)

cblavier avatar cblavier commented on June 6, 2024 3

image

from phoenix_storybook.

matthewsinclair avatar matthewsinclair commented on June 6, 2024 1

Ok, so after some digging, I found the issue. It was that I wasn't properly specifying the attributes in the story. This led to a death spiral that was not reported in an obvious way. I stuck some debug code into a couple of Storyboard modules and I could see that the attributes: property was nil and this meant that when I referenced one of the attributes in the component, it borked.

For the record, my Header1 story now looks like this:

defmodule Storybook.ChromeComponents.Header1 do
  use PhoenixStorybook.Story, :component
  alias Elixir.MultiplyerWeb.ChromeComponents

  def function, do: &ChromeComponents.header1/1

  def attributes, do: [%Attr{ id: :current_user, type: :map }, %Attr{ id: :class, type: :string}]

  def variations do
    [
      %Variation{
        id: :default,
        description: "Default Header",
        attributes: %{ current_user: %{ email: "[email protected]"} },
        slots: []
      }
    ]
  end
end

The new problem is that now it all compiles and displays (mostly) properly, but the actual HTML/CSS from the components is not being emitted properly into the Playground | Preview tab.

This is what I am seeing:
image

I will keep digging ...

from phoenix_storybook.

matthewsinclair avatar matthewsinclair commented on June 6, 2024 1

Aha! And now I know why the component HTML isn't displaying. It is there, but it's a <header...> HTML component, so of course that isn't going to show up inside a random <div...> in the middle of the page. 🤦‍♂️

So, this is solved, but now I have an entirely different issue!

from phoenix_storybook.

matthewsinclair avatar matthewsinclair commented on June 6, 2024 1

Wow! My friend, you are a legend!

It's funny, just before you sent this thru I was looking at the other docs on "Late evaluation" and was wondering what that was all about.

Thanks again for taking the time here! Very much appreciated.

from phoenix_storybook.

cblavier avatar cblavier commented on June 6, 2024

coding is walking from one issue to another, it seems you are in the right direction
feel free to open another ticket if you need help, I'm not super fast to answer but I still try to do my best!

from phoenix_storybook.

matthewsinclair avatar matthewsinclair commented on June 6, 2024

Yeah, it sure is. I have now managed to get all of the values that I need populated for the AshAuthentication form, but I am now getting a doozy of an error that looks like something is going wrong with the parsing of the .story.exs file.

The Story looks like this:

defmodule MultiplyerWeb.Storybook.AuthLive.AuthForm do
  use PhoenixStorybook.Story, :live_component

  # required
  def component, do: MultiplyerWeb.AuthLive.AuthForm

  def attributes do
    [
      %Attr{
        id: :current_user,
        type: :map
      },
      %Attr{
        id: :class,
        type: :string
      },
      %Attr{
        id: :is_register?,
        type: :boolean
      },
      %Attr{
        id: :form,
        type: AshPhoenix.Form
      },
      %Attr{
        id: :trigger_action,
        type: :string
      },
      %Attr{
        id: :action,
        type: :string
      },
      %Attr{
        id: :myself,
        type: :map
      },
      %Attr{
        id: :cta,
        type: :string
      },
      %Attr{
        id: :errors,
        type: :boolean
      }
    ]
  end

  def variations do
    [
      %Variation{
        id: :sign_in_with_password,
        description: "AuthForm: sign in with password",
        attributes: %{
          current_user: %{email: "[email protected]"},
          class: "",
          is_register?: false,
          form: AshPhoenix.Form.for_read(Multiplyer.Accounts.User, :sign_in_with_password),
          cta: "Sign-in",
          action: "sign-in",
          errors: false
        },
        slots: []
      }
    ]
  end
end

And the error when it tries to recompile looks like this:

[debug] compiling storybook file: live_components/auth_live/auth_form.story.exs
[info] Sent 500 in 100ms
[error] #PID<0.1723.0> running Phoenix.Endpoint.SyncCodeReloadPlug (connection #PID<0.1170.0>, stream id 22) terminated
Server: localhost:4000 (http)
Request: GET /storybook/live_components/auth_live/auth_form
** (exit) an exception was raised:
    ** (TokenMissingError) nofile:1:6665: missing terminator: ] (for "[" starting at line 1)
    |
  1 | %{data: nil, id: "form", name: "form", type: :read, opts: [as: "form", warn_on_unhandled_errors?: true], forms: %{}, params: %{}, resource: Multiplyer.Accounts.User, source: %{timeout: nil, offset: 0, select: nil, sort: [], context: %{private: %{}}, load: [], filter: %{resource: Multiplyer.Accounts.User, __struct__: Ash.Filter, expression: %{left: %{attribute: %{default: nil, name: :email, type: Ash.Type.CiString, description: nil, source: :email, __struct__: Ash.Resource.Attribute, constraints: [casing: nil, allow_empty?: false, trim?: true], allow_nil?: false, private?: false, sensitive?: false, always_select?: false, filterable?: true, generated?: false, match_other_defaults?: false, primary_key?: false, update_default: nil, writable?: true}, resource: Multiplyer.Accounts.User, __struct__: Ash.Query.Ref, simple_equality?: nil, bare?: nil, input?: false, relationship_path: []}, right: nil, operator: :==, __struct__: Ash.Query.Operator.Eq, embedded?: false, __predicate__?: true, __operator__?: true}}, arguments: %{}, lock: nil, params: %{}, limit: nil, resource: Multiplyer.Accounts.User, __struct__: Ash.Query, errors: [%{type: :argument, path: [], stacktrace: %{stacktrace: [{Ash.Query, :"-require_arguments/2-fun-0-", 2, [file: ~c"lib/ash/query/query.ex", line: 499]}, {Enum, :"-reduce/3-lists^foldl/2-0-", 3, [file: ~c"lib/enum.ex", line: 2510]}, {Ash.Query, :for_read, 4, [file: ~c"lib/ash/query/query.ex", line: 437]}, {AshPhoenix.Form, :for_read, 3, [file: ~c"lib/ash_phoenix/form/form.ex", line: 798]}, {MultiplyerWeb.Storybook.AuthLive.AuthForm, :variations, 0, [file: ~c"storybook/live_components/auth_live/auth_form.story.exs", line: 57]}, {PhoenixStorybook.StoryLive, :"-render_content/2-fun-6-", 2, [file: ~c"lib/phoenix_storybook/live/story_live.ex", line: 361]}, {Phoenix.LiveView.Diff, :traverse, 7, [file: ~c"lib/phoenix_live_view/diff.ex", line: 386]}, {Phoenix.LiveView.Diff, :"-traverse_dynamic/7-fun-0-", 4, [file: ~c"lib/phoenix_live_view/diff.ex", line: 538]}, {Enum, :"-reduce/3-lists^foldl/2-0-", 3, [file: ~c"lib/enum.ex", line: 2510]}, {Phoenix.LiveView.Diff, :traverse, 7, [file: ~c"lib/phoenix_live_view/diff.ex", line: 384]}, {Phoenix.LiveView.Diff, :"-traverse_dynamic/7-fun-0-", 4, [file: ~c"lib/phoenix_live_view/diff.ex", line: 538]}, {Enum, :"-reduce/3-lists^foldl/2-0-", 3, [file: ~c"lib/enum.ex", line: 2510]}, {Phoenix.LiveView.Diff, :traverse, 7, [file: ~c"lib/phoenix_live_view/diff.ex", line: 384]}, {Phoenix.LiveView.Diff, :render, 3, [file: ~c"lib/phoenix_live_view/diff.ex", line: 136]}, {Phoenix.LiveView.Static, :to_rendered_content_tag, 4, [file: ~c"lib/phoenix_live_view/static.ex", line: 252]}, {Phoenix.LiveView.Static, :render, 3, [file: ~c"lib/phoenix_live_view/static.ex", line: 135]}, {Phoenix.LiveView.Controller, :live_render, 3, [file: ~c"lib/phoenix_live_view/controller.ex", line: 39]}, {Phoenix.Router, :__call__, 5, [file: ~c"lib/phoenix/router.ex", line: 430]}], __struct__: Ash.Error.Stacktrace}, resource: Multiplyer.Accounts.User, __struct__: Ash.Error.Query.Required, vars: [], __exception__: true, field: :password, query: nil, class: :invalid, error_context: [], changeset: nil}, %{type: :argument, path: [], stacktrace: %{stacktrace: [{Ash.Query, :"-require_arguments/2-fun-0-", 2, [file: ~c"lib/ash/query/query.ex", line: 499]}, {Enum, :"-reduce/3-lists^foldl/2-0-", 3, [file: ~c"lib/enum.ex", line: 2510]}, {Ash.Query, :for_read, 4, [file: ~c"lib/ash/query/query.ex", line: 437]}, {AshPhoenix.Form, :for_read, 3, [file: ~c"lib/ash_phoenix/form/form.ex", line: 798]}, {MultiplyerWeb.Storybook.AuthLive.AuthForm, :variations, 0, [file: ~c"storybook/live_components/auth_live/auth_form.story.exs", line: 57]}, {PhoenixStorybook.StoryLive, :"-render_content/2-fun-6-", 2, [file: ~c"lib/phoenix_storybook/live/story_live.ex", line: 361]}, {Phoenix.LiveView.Diff, :traverse, 7, [file: ~c"lib/phoenix_live_view/diff.ex", line: 386]}, {Phoenix.LiveView.Diff, :"-traverse_dynamic/7-fun-0-", 4, [file: ~c"lib/phoenix_live_view/diff.ex", line: 538]}, {Enum, :"-reduce/3-lists^foldl/2-0-", 3, [file: ~c"lib/enum.ex", line: 2510]}, {Phoenix.LiveView.Diff, :traverse, 7, [file: ~c"lib/phoenix_live_view/diff.ex", line: 384]}, {Phoenix.LiveView.Diff, :"-traverse_dynamic/7-fun-0-", 4, [file: ~c"lib/phoenix_live_view/diff.ex", line: 538]}, {Enum, :"-reduce/3-lists^foldl/2-0-", 3, [file: ~c"lib/enum.ex", line: 2510]}, {Phoenix.LiveView.Diff, :traverse, 7, [file: ~c"lib/phoenix_live_view/diff.ex", line: 384]}, {Phoenix.LiveView.Diff, :render, 3, [file: ~c"lib/phoenix_live_view/diff.ex", line: 136]}, {Phoenix.LiveView.Static, :to_rendered_content_tag, 4, [file: ~c"lib/phoenix_live_view/static.ex", line: 252]}, {Phoenix.LiveView.Static, :render, 3, [file: ~c"lib/phoenix_live_view/static.ex", line: 135]}, {Phoenix.LiveView.Controller, :live_render, 3, [file: ~c"lib/phoenix_live_view/controller.ex", line: 39]}, {Phoenix.Router, :__call__, 5, [file: ~c"lib/phoenix/router.ex", line: 430]}], __struct__: Ash.Error.Stacktrace}, resource: Multiplyer.Accounts.User, __struct__: Ash.Error.Query.Required, vars: [], __exception__: true, field: :email, query: nil, class: :invalid, error_context: [], changeset: nil}], action: %{name: :sign_in_with_password, type: :read, description: "Attempt to sign in using a username and password.", manual: nil, filter: nil, metadata: [%{default: nil, name: :token, type: Ash.Type.String, description: "A JWT which the user can use to authenticate to the API.", __struct__: Ash.Resource.Actions.Metadata, constraints: [allow_empty?: false, trim?: true], allow_nil?: false}], arguments: [%{default: nil, name: :email, type: Ash.Type.CiString, description: "The identity to use for retrieving the user.", __struct__: Ash.Resource.Actions.Argument, constraints: [casing: nil, allow_empty?: false, trim?: true], allow_nil?: false, private?: false, sensitive?: false}, %{default: nil, name: :password, type: Ash.Type.String, description: "The password to check for the matching user.", __struct__: Ash.Resource.Actions.Argument, constraints: [allow_empty?: false, trim?: true], allow_nil?: false, private?: false, sensitive?: true}], __struct__: Ash.Resource.Actions.Read, get_by: [], preparations: [%{__struct__: Ash.Resource.Preparation, preparation: {AshAuthentication.Strategy.Password.SignInPreparation, []}}], get?: true, modify_query: nil, pagination: false, primary?: false, touches_resources: [], transaction?: false}, valid?: false, phase: :preparing, distinct: nil, aggregates: %{}, calculations: %{}, tenant: nil, api: nil, after_action: [#Function<1.91439281/2 in AshAuthentication.Strategy.Password.SignInPreparation.prepare/3>], load_through: %{}, invalid_keys: %{map: %{}, __struct__: MapSet}, around_transaction: [], before_action: [#Function<0.91439281/1 in AshAuthentication.Strategy.Password.SignInPreparation.prepare/3>], distinct_sort: [], __validated_for_action__: :sign_in_with_password, action_failed?: false}, __struct__: AshPhoenix.Form, errors: nil, action: :sign_in_with_password, valid?: false, method: "post", api: nil, changed?: false, transform_errors: nil, form_keys: [], any_removed?: false, touched_forms: %{map: %{}, __struct__: MapSet}, added?: false, just_submitted?: false, submit_errors: nil, warn_on_unhandled_errors?: true, prepare_source: nil, transform_params: nil, prepare_params: nil, original_data: nil, submitted_once?: false}
    |                                                                                                                                                                                                                                                                                                                                                                                 (truncated)

That's quite the debug dump! I have no idea where to even look to sort this one out! 🤷

from phoenix_storybook.

cblavier avatar cblavier commented on June 6, 2024

This is equally hard for me to debug :)
It seems that the form attribute is causing the issue but I still don't get why.

Can you open a repo with a minimal story reproducing the issue?
You can fork https://github.com/phenixdigital/phoenix_storybook_sample and create a new story in it

from phoenix_storybook.

matthewsinclair avatar matthewsinclair commented on June 6, 2024

In order to do that, I would need to add Ash and Ash Authentication to it. What about I give you access to my repo? It's actually a pretty simple test app that I am working with. I'm trying to build an Ash app, and I have a non-trivial front-end template that I'm cutting up and trying to implement as a shell app in Elixir/Phoenix/Ash. If I add @cblavier to my repo, you could dl it and see it working (or not working, as the case may be) in situ. The app is not much more complex than the sample app, but it already has Ash/etc in it, so it will be a bit easier (I think). Would that work?

from phoenix_storybook.

cblavier avatar cblavier commented on June 6, 2024

ok, let's do that
I'll have a look later this week

from phoenix_storybook.

matthewsinclair avatar matthewsinclair commented on June 6, 2024

Ok, I have added you to the repo. If you start it up on localhost and visit this URL, you will see the problem:

http://localhost:4000/storybook/live_components/auth_live/auth_form

[debug] compiling storybook file: live_components/auth_live/auth_form.story.exs
[info] Sent 500 in 452ms
[error] #PID<0.1341.0> running Phoenix.Endpoint.SyncCodeReloadPlug (connection #PID<0.1340.0>, stream id 1) terminated
Server: localhost:4000 (http)
Request: GET /storybook/live_components/auth_live/auth_form
** (exit) an exception was raised:
    ** (TokenMissingError) nofile:1:9571: missing terminator: ] (for "[" starting at line 1)
    |
  1 | %{data: nil, id: "form", name: "form", type: :create, opts: [as: "form", warn_on_unhandled_errors?: true], forms: %{}, params: %{}, resource: Multiplyer...<snip>

Let me know how you go. And thanks a ton for doing this!

PS: Please forgive my (very bad!) JS and other front-end content. I am using Storybook as a way to teach myself from scratch how a modern front-end works.

from phoenix_storybook.

cblavier avatar cblavier commented on June 6, 2024

Just nailed it, with a feature I even forgot I wrote 😅

You need to use late evaluation otherwise the evaluation of the AshPhoenix.Form at compile time totally messes up the component code and would also give you the following code preview which is something you probably don't want ;-)

CleanShot 2023-10-05 at 14 48 07

So you need to turn this line:

form: AshPhoenix.Form.for_create(Multiplyer.Accounts.User, :register_with_password),

into this

form: {:eval, ~s|AshPhoenix.Form.for_create(Multiplyer.Accounts.User, :register_with_password)|},

CleanShot 2023-10-05 at 14 49 37

from phoenix_storybook.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.