Add LiveView table component (#2460)

This commit is contained in:
Paulo Valim 2024-01-30 10:41:48 +01:00 committed by GitHub
parent 60d7dd74c3
commit 714417189b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 123 additions and 58 deletions

View file

@ -739,4 +739,87 @@ defmodule LivebookWeb.CoreComponents do
def hook_prop(value) do
Jason.encode!(value)
end
@doc ~S"""
Renders a table with generic styling.
## Examples
<.table id="users" rows={@users}>
<:col :let={user} label="id"><%= user.id %></:col>
<:col :let={user} label="username"><%= user.username %></:col>
</.table>
"""
attr :id, :string, required: true
attr :rows, :list, required: true
attr :row_id, :any, default: nil, doc: "the function for generating the row id"
attr :row_click, :any, default: nil, doc: "the function for handling phx-click on each row"
attr :row_item, :any,
default: &Function.identity/1,
doc: "the function for mapping each row before calling the :col and :action slots"
slot :col, required: true do
attr :label, :string
end
slot :action, doc: "the slot for showing user actions in the last table column"
def table(assigns) do
assigns =
with %{rows: %Phoenix.LiveView.LiveStream{}} <- assigns do
assign(assigns, row_id: assigns.row_id || fn {id, _item} -> id end)
end
~H"""
<div class="overflow-y-auto px-4 sm:overflow-visible sm:px-0">
<table class="min-w-full divide-y divide-gray-300">
<thead>
<tr>
<th
:for={col <- @col}
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6"
>
<%= col[:label] %>
</th>
<th
:if={@action != []}
class="py-3.5 pl-3 pr-5 text-right text-sm font-semibold text-gray-900 sm:pr-7"
>
<span>Actions</span>
</th>
</tr>
</thead>
<tbody
id={@id}
phx-update={match?(%Phoenix.LiveView.LiveStream{}, @rows) && "stream"}
class="divide-y divide-gray-200 bg-white"
>
<tr :for={row <- @rows} id={@row_id && @row_id.(row)} class="group hover:bg-gray-50">
<td
:for={{col, i} <- Enum.with_index(@col)}
phx-click={@row_click && @row_click.(row)}
class={["relative p-0", @row_click && "hover:cursor-pointer"]}
>
<div class="block p-4 sm:px-6">
<span class="absolute -inset-y-px right-0 -left-4 group-hover:bg-gray-100 sm:rounded-l-xl" />
<span class={["relative", i == 0 && "text-sm font-medium text-gray-900"]}>
<%= render_slot(col, @row_item.(row)) %>
</span>
</div>
</td>
<td :if={@action != []} class="relative p-0">
<div class="relative whitespace-nowrap py-4 pl-3 pr-4 text-sm font-medium sm:pr-6 flex justify-end items-center">
<span class="absolute -inset-y-px -right-4 left-0 group-hover:bg-gray-100 sm:rounded-r-xl" />
<span :for={action <- @action} class="relative ml-4">
<%= render_slot(action, @row_item.(row)) %>
</span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
"""
end
end

View file

@ -19,66 +19,46 @@ defmodule LivebookWeb.Hub.SecretListComponent do
No secrets here... yet!
</.no_entries>
<div :if={@secrets != []}>
<table class="min-w-full divide-y divide-gray-300">
<thead>
<tr>
<th
scope="col"
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6"
<.table id="hub-secrets-table" rows={@secrets}>
<:col :let={secret} label="Name"><%= secret.name %></:col>
<:action :let={secret}>
<span class="tooltip left" data-tooltip="Edit">
<.link
id={"hub-secret-#{secret.name}-edit"}
patch={"/#{@edit_path}/#{secret.name}"}
type="button"
role="menuitem"
class="icon-button"
>
Name
</th>
<th
scope="col"
class="py-3.5 pl-3 pr-6 text-right text-sm font-semibold text-gray-900 sm:pr-8"
<.remix_icon icon="edit-fill" class="text-lg" />
</.link>
</span>
</:action>
<:action :let={secret}>
<span class="tooltip left" data-tooltip="Delete">
<button
id={"hub-secret-#{secret.name}-delete"}
type="button"
phx-click={
JS.push("delete_hub_secret",
value: %{
name: secret.name,
value: secret.value,
hub_id: secret.hub_id,
deployment_group_id: secret.deployment_group_id,
return_to: @return_to
},
target: @myself
)
}
role="menuitem"
class="icon-button"
>
Actions
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 bg-white">
<tr :for={secret <- @secrets}>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6">
<%= secret.name %>
</td>
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 flex justify-end items-center gap-4 text-sm font-medium sm:pr-6">
<span class="tooltip left" data-tooltip="Edit">
<.link
id={"hub-secret-#{secret.name}-edit"}
patch={"/#{@edit_path}/#{secret.name}"}
type="button"
role="menuitem"
class="icon-button"
>
<.remix_icon icon="edit-fill" class="text-lg" />
</.link>
</span>
<span class="tooltip left" data-tooltip="Delete">
<button
id={"hub-secret-#{secret.name}-delete"}
type="button"
phx-click={
JS.push("delete_hub_secret",
value: %{
name: secret.name,
value: secret.value,
hub_id: secret.hub_id,
deployment_group_id: secret.deployment_group_id,
return_to: @return_to
},
target: @myself
)
}
role="menuitem"
class="icon-button"
>
<.remix_icon icon="delete-bin-6-line" class="text-lg" />
</button>
</span>
</td>
</tr>
</tbody>
</table>
<.remix_icon icon="delete-bin-6-line" class="text-lg" />
</button>
</span>
</:action>
</.table>
</div>
</div>
<div class="flex">

View file

@ -13,9 +13,11 @@
"ecto": {:hex, :ecto, "3.10.3", "eb2ae2eecd210b4eb8bece1217b297ad4ff824b4384c0e3fdd28aaf96edd6135", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44bec74e2364d491d70f7e42cd0d690922659d329f6465e89feb8a34e8cd3433"},
"eini": {:hex, :eini_beam, "2.2.3", "4c809b483b0435789c5924642b81ed1cd6fa7d23f5e2efb3e420522a051fa483", [:rebar3], [], "hexpm", "10381b4cb76b8340b492653dae8f6ab7cb372305906ea196d6a1c070516e7a5f"},
"ex_doc": {:hex, :ex_doc, "0.30.9", "d691453495c47434c0f2052b08dd91cc32bc4e1a218f86884563448ee2502dd2", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "d7aaaf21e95dc5cddabf89063327e96867d00013963eadf2c6ad135506a8bc10"},
"expo": {:hex, :expo, "0.5.1", "249e826a897cac48f591deba863b26c16682b43711dd15ee86b92f25eafd96d9", [:mix], [], "hexpm", "68a4233b0658a3d12ee00d27d37d856b1ba48607e7ce20fd376958d0ba6ce92b"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"finch": {:hex, :finch, "0.16.0", "40733f02c89f94a112518071c0a91fe86069560f5dbdb39f9150042f44dcfb1a", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f660174c4d519e5fec629016054d60edd822cdfe2b7270836739ac2f97735ec5"},
"floki": {:hex, :floki, "0.34.3", "5e2dcaec5d7c228ce5b1d3501502e308b2d79eb655e4191751a1fe491c37feac", [:mix], [], "hexpm", "9577440eea5b97924b4bf3c7ea55f7b8b6dce589f9b28b096cc294a8dc342341"},
"gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"},
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
"iso8601": {:hex, :iso8601, "1.3.3", "994aff5dfe760f14a8c4f2d8c3cf500371bf1a8cf309c3c0cb510401064223e0", [:rebar3], [], "hexpm", "bcc7767d691e4d8a26e713f48da51abd951bec4e071ae841f371766f96b46834"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},