From e49ea8b55f5bf79b475cabb71fb1ff77a2ff8fbb Mon Sep 17 00:00:00 2001 From: Sergey Semenov Date: Thu, 5 Oct 2023 09:16:36 +0200 Subject: [PATCH] feat: Phoenix.Stream for Table component (#739) --- config/dev.exs | 2 + lib/moon/design/table.ex | 20 ++++- .../examples/design/table_example/stream.ex | 85 +++++++++++++++++++ lib/moon_web/pages/design/table_page.ex | 10 +++ .../breadcrumb/five_and_more_items_test.exs | 2 +- test/moon_web/pages/examples_test.exs | 1 + 6 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 lib/moon_web/examples/design/table_example/stream.ex diff --git a/config/dev.exs b/config/dev.exs index 2e94cc721..7f0ccc841 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -61,3 +61,5 @@ config :phoenix, :stacktrace_depth, 20 # Initialize plugs at runtime for faster development compilation config :phoenix, :plug_init_mode, :runtime + +# config :phoenix_live_view, debug_heex_annotations: true diff --git a/lib/moon/design/table.ex b/lib/moon/design/table.ex index b9b109ec3..ce16a2750 100644 --- a/lib/moon/design/table.ex +++ b/lib/moon/design/table.ex @@ -13,7 +13,7 @@ defmodule Moon.Design.Table do @doc "Sorting of the table, format [field:, \"ASC\"|\"DESC\"]. If given, component will sort given items before displaying" prop(sort, :keyword, default: []) - @doc "The list of items to be rendered. If item does not have id - than index is used instead" + @doc "The list of items to be rendered. If item does not have id - than index is used instead. Able to work with streams" prop(items, :generator, required: true) @doc "Event that firset on row click" @@ -64,6 +64,9 @@ defmodule Moon.Design.Table do @doc "Additional classes for a table tag" prop(class, :css_class) + @doc "Additional attributes for tbody tag" + prop(body_attrs, :map, default: %{}) + def render(assigns) do ~F""" - - {#for {item, row_index} <- Enum.with_index(@items |> add_index_as |> sort_items(@sort))} + + {#for {row_index, item} <- stream_data(assigns)} "text-moon-14 py-5 px-3" end end + + defp stream_data(%{items: stream = %Phoenix.LiveView.LiveStream{}}) do + stream + end + + defp stream_data(%{items: items, sort: sort}) when is_list(items) do + items + |> add_index_as() + |> sort_items(sort) + |> Enum.with_index(&{&2, &1}) + end end diff --git a/lib/moon_web/examples/design/table_example/stream.ex b/lib/moon_web/examples/design/table_example/stream.ex new file mode 100644 index 000000000..242dee48d --- /dev/null +++ b/lib/moon_web/examples/design/table_example/stream.ex @@ -0,0 +1,85 @@ +defmodule MoonWeb.Examples.Design.TableExample.Stream do + @moduledoc false + + use Moon.LiveView + use MoonWeb, :example + + alias Moon.Design.Table + alias Moon.Design.Table.Column + alias Moon.Components.Renderers.Datetime + + def mount(_params, _session, socket) do + {:ok, stream(socket, :models, models())} + end + + defp models() do + Enum.map(1..5, fn x -> + %{ + id: x, + name: "Name #{x}", + created_at: DateTime.add(DateTime.utc_now(), -3600 + x) + } + end) + end + + def render(assigns) do + ~F""" +
+
"stream"}}> + + {model.id} + + + {model.name} + + + + +
+ + """ + end + + def code() do + """ + use Phoenix.LiveView + + alias Moon.Design.Table + alias Moon.Design.Table.Column + alias Moon.Components.Renderers.Datetime + + def mount(_params, _session, socket) do + {:ok, stream(socket, :models, models())} + end + + defp models() do + Enum.map(1..5, fn x -> + %{ + id: x, + name: "Name \#{x}", + created_at: DateTime.add(DateTime.utc_now(), -3600 + x) + } + end) + end + + def render(assigns) do + ~F\""" +
+ "stream"}}> + + {model.id} + + + {model.name} + + + + +
+
+ \""" + end + + """ + end +end diff --git a/lib/moon_web/pages/design/table_page.ex b/lib/moon_web/pages/design/table_page.ex index 927161f14..248e21ee8 100644 --- a/lib/moon_web/pages/design/table_page.ex +++ b/lib/moon_web/pages/design/table_page.ex @@ -5,11 +5,14 @@ defmodule MoonWeb.Pages.Design.TablePage do alias Moon.Design.Table alias MoonWeb.Components.Page + alias MoonWeb.Components.ExampleAndCode alias MoonWeb.Components.ComponentPageDescription alias MoonWeb.Components.PropsTable alias MoonWeb.Components.ExamplesList alias MoonWeb.Examples.Design.TableExample + # import Phoenix.Component, only: [live_render: 3] + data(breadcrumbs, :any, default: [ %{ @@ -50,6 +53,13 @@ defmodule MoonWeb.Pages.Design.TablePage do TableExample.Responsive ]} /> + + <:example> + + + <:code>{TableExample.Stream.code()} + + diff --git a/test/moon_web/examples/breadcrumb/five_and_more_items_test.exs b/test/moon_web/examples/breadcrumb/five_and_more_items_test.exs index 86b286c88..500fa8a7e 100644 --- a/test/moon_web/examples/breadcrumb/five_and_more_items_test.exs +++ b/test/moon_web/examples/breadcrumb/five_and_more_items_test.exs @@ -4,7 +4,7 @@ defmodule MoonWeb.Examples.Breadcrumb.FiveAndMoreItemsTest do # TODO: fix test test "should open and close Breadcrumb panel", %{conn: conn} do - {:ok, view, _html} = live(conn, "/example/BreadcrumbExample.FiveAndMoreItems") + {:ok, _view, _html} = live(conn, "/example/BreadcrumbExample.FiveAndMoreItems") # assert view # |> element("#breadcrumb_5 ol.hidden[id=breadcrumb_5_inner_breadcrumb_flyout]") diff --git a/test/moon_web/pages/examples_test.exs b/test/moon_web/pages/examples_test.exs index a458015b7..8ef0e2a55 100644 --- a/test/moon_web/pages/examples_test.exs +++ b/test/moon_web/pages/examples_test.exs @@ -10,6 +10,7 @@ defmodule MoonWeb.Pages.ExamplesTest do with {:ok, list} <- :application.get_key(:moon, :modules) do list |> Enum.filter(&(&1 |> Module.split() |> Enum.take(2) == ~w|MoonWeb Examples|)) + |> Enum.filter(&(&1 != MoonWeb.Examples.Design.TableExample.Stream)) |> Enum.each(fn example -> path = MoonWeb.Router.Helpers.live_path(