Skip to content
Merged
2 changes: 2 additions & 0 deletions assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import LiveMetricsEChart from "./hooks/live_metrics_echart";
import ObserverEChart from "./hooks/observer_echart";
import ScrollBottom from "./hooks/scroll_bottom";
import Themer from "./hooks/themer";
import AutoDismissFlash from "./hooks/auto_dismiss_flash";

const hooks = {
LiveMetricsEChart,
ObserverEChart,
ScrollBottom,
Themer,
AutoDismissFlash,
};

// Topbar ---
Expand Down
11 changes: 11 additions & 0 deletions assets/js/hooks/auto_dismiss_flash.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const AutoDismissFlash = {
mounted() {
setTimeout(() => {
this.el.style.transition = "opacity 0.5s";
this.el.style.opacity = "0";
setTimeout(() => this.pushEventTo(this.el, "clear-flash"), 500);
}, 3500);
},
};

export default AutoDismissFlash
2 changes: 1 addition & 1 deletion assets/js/hooks/observer_echart.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const ObserverEChart = {
// Compare the new option series with the previous one
if (this.previousSeries && JSON.stringify(this.previousSeries) === JSON.stringify(newOption.series)) {
// If the data is the same, skip the update
console.log('No changes in the data, skipping setOption');
// console.log('[ObserverEChart] No changes in the data, skipping setOption');
return; // Exit without updating the chart
}

Expand Down
29 changes: 18 additions & 11 deletions lib/observer_web/apps/process.ex
Original file line number Diff line number Diff line change
Expand Up @@ -99,17 +99,24 @@ defmodule ObserverWeb.Apps.Process do
gc = Keyword.get(data, :garbage_collection, [])
dictionary = Keyword.get(data, :dictionary)

{state, phx_lv_socket} =
case state(pid, timeout) do
{:ok, %{socket: %Phoenix.LiveView.Socket{}} = state} ->
new_state = %{state | socket: "Phoenix.LiveView.Socket", components: "hidden"}
{to_string(:io_lib.format("~tp", [new_state])), state.socket}

{:ok, state} ->
{to_string(:io_lib.format("~tp", [state])), nil}
meta = structure_meta(data, pid)

{:error, reason} ->
{reason, nil}
{state, phx_lv_socket} =
if meta.class in [:unknown, :application] do
{"Could not retrieve the state for pid: #{inspect(pid)}. Reason: state is not available - see Overview class for more information",
nil}
else
case state(pid, timeout) do
{:ok, %{socket: %Phoenix.LiveView.Socket{}} = state} ->
new_state = %{state | socket: "Phoenix.LiveView.Socket", components: "hidden"}
{to_string(:io_lib.format("~tp", [new_state])), state.socket}

{:ok, state} ->
{to_string(:io_lib.format("~tp", [state])), nil}

{:error, reason} ->
{reason, nil}
end
end

%{
Expand All @@ -134,7 +141,7 @@ defmodule ObserverWeb.Apps.Process do
gc_min_heap_size: Keyword.get(gc, :min_heap_size, 0),
gc_full_sweep_after: Keyword.get(gc, :fullsweep_after, 0)
},
meta: structure_meta(data, pid),
meta: meta,
state: state,
dictionary: dictionary,
phx_lv_socket: phx_lv_socket
Expand Down
74 changes: 74 additions & 0 deletions lib/web/components/confirm.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
defmodule Observer.Web.Components.Confirm do
@moduledoc false
use Phoenix.Component

attr :id, :string, required: true
slot :header, required: true
slot :footer, required: true
slot :inner_block, required: true

def content(assigns) do
~H"""
<div id={@id}>
<div
class="fixed inset-0 z-20 overflow-y-auto"
phx-window-keydown="confirm-close-modal"
phx-key="escape"
>
<div class="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 bg-white/75 transition-opacity" aria-hidden="true"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
&#8203;
</span>
<div class="inline-block overflow-hidden text-left align-bottom bg-white border border-gray-200 shadow-md rounded-md transform transition-all sm:my-8 sm:align-middle sm:max-w-md sm:w-full">
<div class="p-6 mx-auto mb-2 bg-white">
<header class="mb-6 text-center">
<h3 class="mb-3 text-lg font-bold text-gray-900">
{render_slot(@header)}
</h3>
</header>
{render_slot(@inner_block)}
<footer class="flex mt-6 gap-x-10">
{render_slot(@footer)}
</footer>
</div>
</div>
</div>
</div>
</div>
"""
end

attr :id, :string, required: true
slot :inner_block, required: true

def cancel_button(assigns) do
~H"""
<button
id={"cancel-button-#{@id}"}
class="flex-1 px-4 py-2 border border-gray-800 rounded-full"
phx-click="confirm-close-modal"
>
{render_slot(@inner_block)}
</button>
"""
end

attr :id, :string, required: true
attr :value, :string, required: true
attr :event, :string, required: true
slot :inner_block, required: true

def confirm_button(assigns) do
~H"""
<button
id={"confirm-button-#{@id}"}
class="flex-1 px-4 py-2 text-white bg-blue-600 rounded-full"
phx-click={@event}
phx-value-id={@value}
>
{render_slot(@inner_block)}
</button>
"""
end
end
16 changes: 15 additions & 1 deletion lib/web/components/core.ex
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ defmodule Observer.Web.Components.Core do
def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
assigns
|> assign(field: nil, id: assigns.id || field.id)
# |> assign(:errors, Enum.map(field.errors, &translate_error(&1)))
|> assign(:errors, Enum.map(field.errors, &translate_error(&1)))
|> assign_new(:name, fn -> if assigns.multiple, do: field.name <> "[]", else: field.name end)
|> assign_new(:value, fn -> field.value end)
|> input()
Expand Down Expand Up @@ -438,6 +438,20 @@ defmodule Observer.Web.Components.Core do
"""
end

@doc """
Translates an error message using gettext.
"""
def translate_error({msg, _opts}) do
msg
end

@doc """
Translates the errors for a field from a keyword list of errors.
"""
def translate_errors(errors, field) when is_list(errors) do
for {^field, {msg, opts}} <- errors, do: translate_error({msg, opts})
end

@doc """
Renders a label.
"""
Expand Down
38 changes: 38 additions & 0 deletions lib/web/components/icons.ex
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,44 @@ defmodule Observer.Web.Components.Icons do

attr :rest, :global

def check_circle(assigns) do
~H"""
<.svg_outline {@rest}>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</.svg_outline>
"""
end

attr :rest, :global

def x_mark(assigns) do
~H"""
<.svg_outline {@rest}>
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</.svg_outline>
"""
end

attr :rest, :global

def x_circle(assigns) do
~H"""
<.svg_outline {@rest}>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</.svg_outline>
"""
end

attr :rest, :global

def moon(assigns) do
~H"""
<.svg_outline {@rest}>
Expand Down
74 changes: 74 additions & 0 deletions lib/web/components/layouts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,78 @@ defmodule Observer.Web.Layouts do

defp list_pages_by_params(%{"iframe" => "true"}), do: [:tracing, :applications, :metrics]
defp list_pages_by_params(_params), do: [:root, :tracing, :applications, :metrics]

@doc """
Renders flash notices.

## Examples

<.flash kind={:info} flash={@flash} />
<.flash kind={:info} phx-mounted={show("#flash")}>Welcome Back!</.flash>
"""
attr :id, :string, doc: "the optional id of flash container"
attr :flash, :map, default: %{}, doc: "the map of flash messages to display"
attr :title, :string, default: nil
attr :kind, :atom, values: [:info, :error], doc: "used for styling and flash lookup"
attr :rest, :global, doc: "the arbitrary HTML attributes to add to the flash container"

slot :inner_block, doc: "the optional inner block that renders the flash message"

def flash(assigns) do
assigns = assign_new(assigns, :id, fn -> "flash-#{assigns.kind}" end)

~H"""
<div
:if={msg = render_slot(@inner_block) || Phoenix.Flash.get(@flash, @kind)}
id={@id}
phx-hook="AutoDismissFlash"
phx-click={JS.push("lv:clear-flash", value: %{key: @kind}) |> hide("##{@id}")}
role="alert"
class="fixed z-40 inset-0 flex items-end justify-center pointer-events-none md:py-3 md:px-4 sm:p-6 sm:items-start sm:justify-end"
{@rest}
>
<div class="max-w-sm w-full bg-white dark:bg-black dark:bg-opacity-90 shadow-lg rounded-lg pointer-events-auto">
<div class="rounded-lg ring-1 ring-black/5 overflow-hidden">
<div class="p-4">
<div class="flex items-start">
<%= if @kind == :error do %>
<div class="flex-shrink-0 text-red-400">
<Icons.x_circle />
</div>
<% else %>
<div class="flex-shrink-0 text-green-400">
<Icons.check_circle />
</div>
<% end %>
<div class="ml-3 w-0 flex-1 pt-0.5">
<p class="text-sm leading-5 font-medium text-gray-900 dark:text-gray-100">
{msg}
</p>
</div>
<div class="ml-4 flex-shrink-0 flex">
<button
phx-click="lv:clear-flash"
class="inline-flex text-gray-400 dark:text-gray-600 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 focus:text-gray-500 transition ease-in-out duration-150"
>
<Icons.x_mark class="w-5 h-5" />
</button>
</div>
</div>
</div>
</div>
</div>
</div>
"""
end

def hide(js \\ %JS{}, selector) do
JS.hide(js,
to: selector,
time: 200,
transition:
{"transition-all transform ease-in duration-200",
"opacity-100 translate-y-0 sm:scale-100",
"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"}
)
end
end
2 changes: 2 additions & 0 deletions lib/web/components/layouts/live.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<meta name="live-path" content={@live_path} />

<main class="p-4 min-h-screen flex flex-col">
<.flash :if={Phoenix.Flash.get(@flash, :info)} kind={:info} flash={@flash} />
<.flash :if={Phoenix.Flash.get(@flash, :error)} kind={:error} flash={@flash} />
<header class="flex items-center mb-2">
<div class="md:w-84 mr-3">
<.logo params={@params} />
Expand Down
Loading