Skip to content

Commit

Permalink
feat: Wrap sensitive attribute rendering in a new `SensitiveAttribute…
Browse files Browse the repository at this point in the history
…` live component

This will handle hiding the value by default and having a "click to display" icon

The icon can then be clicked to hide it again
  • Loading branch information
sevenseacat committed Nov 21, 2023
1 parent 652611d commit c107815
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 9 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ Then, you can start the app with: `mix dev`

If you make changes to the resources, you can generate migrations with `mix generate_migrations`

If you make changes to any of the assets (CSS or JavaScript), including updating dependencies that include assets such as LiveView, you will need to recompile the assets with `mix assets.build`.
If you make changes to any of the assets (CSS or JavaScript), including updating dependencies that include assets such as LiveView, you will need to recompile the assets with `mix assets.deploy`.

## Contributors

Expand Down
34 changes: 34 additions & 0 deletions lib/ash_admin/components/resource/sensitive_attribute.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
defmodule AshAdmin.Components.Resource.SensitiveAttribute do
use Phoenix.LiveComponent

import AshAdmin.CoreComponents

def mount(socket) do
{:ok, assign(socket, viewed: false)}
end

def render(assigns) do
assigns = assign(assigns, present?: assigns.value not in [nil, ""])

~H"""
<div>
<span :if={@present? && !@viewed} class="italic">
--redacted--
<span class="cursor-pointer" phx-click="toggle_sensitive_attribute" phx-target={@myself}>
<.icon name="hero-eye-solid" class="w-5 h-5 text-gray-500" />
</span>
</span>
<span :if={@present? && @viewed}>
<%= render_slot(@inner_block) %>
<span class="cursor-pointer" phx-click="toggle_sensitive_attribute" phx-target={@myself}>
<.icon name="hero-eye-slash-solid" class="w-5 h-5 text-gray-500" />
</span>
</span>
</div>
"""
end

def handle_event("toggle_sensitive_attribute", _params, socket) do
{:noreply, assign(socket, viewed: !socket.assigns.viewed)}
end
end
32 changes: 28 additions & 4 deletions lib/ash_admin/components/resource/show.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule AshAdmin.Components.Resource.Show do
@moduledoc false
use Phoenix.LiveComponent

alias AshAdmin.Components.Resource.Table
alias AshAdmin.Components.Resource.{SensitiveAttribute, Table}
import AshAdmin.Helpers
import Tails
import AshAdmin.CoreComponents
Expand Down Expand Up @@ -221,7 +221,9 @@ defmodule AshAdmin.Components.Resource.Show do
}
>
<div class="block text-sm font-medium text-gray-700"><%= to_name(attribute.name) %></div>
<div><%= render_attribute(assigns, @resource, @record, attribute) %></div>
<div>
<%= render_maybe_sensitive_attribute(assigns, @resource, @record, attribute) %>
</div>
</div>
</div>
<div :if={!Enum.empty?(@flags)} class="hidden sm:block" aria-hidden="true">
Expand All @@ -241,7 +243,9 @@ defmodule AshAdmin.Components.Resource.Show do
}
>
<div class="block text-sm font-medium text-gray-700"><%= to_name(attribute.name) %></div>
<div><%= render_attribute(assigns, @resource, @record, attribute) %></div>
<div>
<%= render_maybe_sensitive_attribute(assigns, @resource, @record, attribute) %>
</div>
</div>
</div>
<div :if={!Enum.empty?(@bottom_attributes)} class="hidden sm:block" aria-hidden="true">
Expand All @@ -262,12 +266,32 @@ defmodule AshAdmin.Components.Resource.Show do
}
>
<div class="block text-sm font-medium text-gray-700"><%= to_name(attribute.name) %></div>
<div><%= render_attribute(assigns, @resource, @record, attribute) %></div>
<div>
<%= render_maybe_sensitive_attribute(assigns, @resource, @record, attribute) %>
</div>
</div>
</div>
"""
end

defp render_maybe_sensitive_attribute(assigns, resource, record, attribute) do
assigns = assign(assigns, attribute: attribute)

if attribute.sensitive? do
~H"""
<.live_component
id={"#{@record.id}-#{@attribute.name}"}
module={SensitiveAttribute}
value={Map.get(@record, @attribute.name)}
>
<%= render_attribute(assigns, @resource, @record, @attribute) %>
</.live_component>
"""
else
render_attribute(assigns, resource, record, attribute)
end
end

defp render_attribute(assigns, resource, record, attribute, nested? \\ false)

defp render_attribute(
Expand Down
21 changes: 20 additions & 1 deletion lib/ash_admin/components/resource/table.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ defmodule AshAdmin.Components.Resource.Table do
import AshAdmin.Helpers
import AshAdmin.CoreComponents
alias Ash.Resource.Relationships.{BelongsTo, HasOne}
alias AshAdmin.Components.Resource.SensitiveAttribute

attr :attributes, :any, default: nil
attr :data, :list, default: nil
Expand Down Expand Up @@ -135,13 +136,31 @@ defmodule AshAdmin.Components.Resource.Table do
|> Map.get(attribute.name)
|> (&apply(mod, func, [&1] ++ args)).()

format_attribute_value(data, attribute)
if struct == Ash.Resource.Attribute && attribute.sensitive? do
format_sensitive_value(data, attribute, record)
else
format_attribute_value(data, attribute)
end
end

defp process_attribute(_api, _record, _attr, _formats, _actor) do
"..."
end

defp format_sensitive_value(value, attribute, record) do
assigns = %{value: value, attribute: attribute, record: record}

~H"""
<.live_component
id={"#{@record.id}-#{@attribute.name}"}
module={SensitiveAttribute}
value={@value}
>
<%= format_attribute_value(@value, @attribute) %>
</.live_component>
"""
end

defp format_attribute_value(data, %{type: Ash.Type.Binary}) when data not in [[], nil, ""] do
assigns = %{}

Expand Down
2 changes: 1 addition & 1 deletion priv/static/assets/app.css

Large diffs are not rendered by default.

Binary file modified priv/static/assets/app.css.gz
Binary file not shown.
4 changes: 2 additions & 2 deletions priv/static/cache_manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"!comment!":"This file was auto-generated by `mix phx.digest`. Remove it and all generated artefacts with `mix phx.digest.clean --all`",
"version":1,
"latest":{"assets/app.css":"assets/app-161d914bba3ef8912bae46d62332075a.css","assets/app.js":"assets/app-aac45a999218cb837d0d4006c02b7dff.js"},
"digests":{"assets/app-161d914bba3ef8912bae46d62332075a.css":{"size":35588,"sha512":"UD0fP1n3WDpLGBt/Z/B2CpSpg8DUFlcIM3LV86qlBW28sgXzM2nOogI6tFmH6IclRlq2VBl+O5Pc+TKkBgHTcg==","digest":"161d914bba3ef8912bae46d62332075a","logical_path":"assets/app.css","mtime":63867247404},"assets/app-aac45a999218cb837d0d4006c02b7dff.js":{"size":108631,"sha512":"Q/jSWd9SG+3D9BjNSTSo3XNU/Q0xBrdwB/OgT7W4clywBHa5VxbBNh0QBT5ZsBfTZ7MANggW8XW9rOM5UVteYg==","digest":"aac45a999218cb837d0d4006c02b7dff","logical_path":"assets/app.js","mtime":63867247404},"assets/app-cdfeb0af86efa39e60bcea317f8c65d5.js":{"digest":"cdfeb0af86efa39e60bcea317f8c65d5","logical_path":"assets/app.js","mtime":63867247325,"sha512":"4cLBcG07unx230U6//4lAjOnKo5FAbYVeHCy/46Fa0UbVVcI0tmfCArbloLf0mEfRgzLZev132DFudJhCydOqQ==","size":108632}}
"latest":{"assets/app.css":"assets/app-f480ad9fb2a3744d668ac31cc919441f.css","assets/app.js":"assets/app-aac45a999218cb837d0d4006c02b7dff.js"},
"digests":{"assets/app-aac45a999218cb837d0d4006c02b7dff.js":{"size":108631,"sha512":"Q/jSWd9SG+3D9BjNSTSo3XNU/Q0xBrdwB/OgT7W4clywBHa5VxbBNh0QBT5ZsBfTZ7MANggW8XW9rOM5UVteYg==","digest":"aac45a999218cb837d0d4006c02b7dff","logical_path":"assets/app.js","mtime":63867771918},"assets/app-f480ad9fb2a3744d668ac31cc919441f.css":{"size":37300,"sha512":"g15iWMXrhNqfFRVkrKH4c9XonkZnDWFEdGuzX0BW319sucBZFfD0lZ8GTgPJcKl3gyhUqH0Lm4jy80LgfFao7w==","digest":"f480ad9fb2a3744d668ac31cc919441f","logical_path":"assets/app.css","mtime":63867771918}}
}

0 comments on commit c107815

Please sign in to comment.