diff --git a/lib/freedive/api/service/cli.ex b/lib/freedive/api/service/cli.ex
index b4d52e6..d6eebe1 100644
--- a/lib/freedive/api/service/cli.ex
+++ b/lib/freedive/api/service/cli.ex
@@ -134,11 +134,11 @@ defmodule Freedive.Api.Service.Cli do
defp service(name, command, args) do
case execute(@service_bin, [name, command] ++ args, doas: true) do
{:ok, stdout} ->
- Logger.debug("service #{name} #{command} #{args}: #{inspect(stdout)}")
+ # Logger.debug("service #{name} #{command} #{args}: #{inspect(stdout)}")
{:ok, stdout}
{:error, {stderr, code}} ->
- Logger.debug("service #{name} #{command} #{args}: (#{code}) #{String.trim(stderr)}")
+ # Logger.debug("service #{name} #{command} #{args}: (#{code}) #{String.trim(stderr)}")
{:error, {stderr, code}}
end
end
diff --git a/lib/freedive/api/service/server.ex b/lib/freedive/api/service/server.ex
index 51a359b..8da5c47 100644
--- a/lib/freedive/api/service/server.ex
+++ b/lib/freedive/api/service/server.ex
@@ -10,6 +10,7 @@ defmodule Freedive.Api.Service do
@events [
:command,
:refreshed,
+ :refreshed_services,
:stdlog
]
@@ -53,12 +54,25 @@ defmodule Freedive.Api.Service do
def init(opts) do
state = %{opts: opts, services: []}
Logger.info("Starting Service.Server with opts: #{inspect(opts)}")
+
{:ok, state, {:continue, opts}}
end
@impl true
def handle_continue(_opts, state) do
- state = %{state | services: list_services!()}
+ {:ok, watcher_pid} =
+ FileSystem.start_link(
+ dirs: ["/etc/", "/usr/local/etc/rc.d"],
+ name: :rc_dirs_changed
+ )
+
+ FileSystem.subscribe(:rc_dirs_changed)
+
+ state =
+ state
+ |> Map.put(:services, list_services!())
+ |> Map.put(:watcher_pid, watcher_pid)
+
{:noreply, state}
end
@@ -88,16 +102,40 @@ defmodule Freedive.Api.Service do
{:noreply, state}
end
+ @impl true
+ def handle_info(
+ {:file_event, watcher_pid, {path, _events}},
+ %{watcher_pid: watcher_pid} = state
+ ) do
+ name = Path.basename(path)
+ Logger.debug("Service.Server: handle_info file_event name: #{name}")
+
+ state =
+ if name in state[:services] do
+ curr_service = state[:services][name]
+ refreshed_service = refresh_service!(curr_service)
+ IO.inspect(refreshed_service, label: "refreshed_service")
+ broadcast(:refreshed, refreshed_service)
+ %{state | services: Map.put(state[:services], name, refreshed_service)}
+ else
+ if name == "rc.conf" do
+ Logger.info("Service.Server: rc.conf changed, refreshing enabled services.")
+ services = list_services!()
+ broadcast(:refreshed_services, services)
+
+ state
+ |> Map.put(:services, services)
+ else
+ state
+ end
+ end
+
+ {:noreply, state}
+ end
+
def broadcast(event, payload) do
if event in @events do
- Phoenix.PubSub.broadcast(
- Freedive.PubSub,
- @topic,
- {event,
- Map.merge(payload, %{
- hostname: "unknown"
- })}
- )
+ Phoenix.PubSub.broadcast(Freedive.PubSub, @topic, {event, payload})
else
Logger.error("Service.Server broadcast: unknown event: #{event}")
end
diff --git a/lib/freedive_web/live/service_live.ex b/lib/freedive_web/live/service_live.ex
index 6bcf1a3..38b1cd8 100644
--- a/lib/freedive_web/live/service_live.ex
+++ b/lib/freedive_web/live/service_live.ex
@@ -99,6 +99,26 @@ defmodule FreediveWeb.ServiceLive do
{:noreply, socket}
+ :refreshed_services ->
+ Logger.info("ServiceLive: Refreshed services.")
+
+ searched_and_filtered_items =
+ payload
+ |> search(socket.assigns.query)
+ |> FreediveWeb.LiliformLive.filter(
+ FreediveWeb.LiliformLive.get_active_filter(socket.assigns.filters)
+ )
+
+ socket =
+ if socket.assigns.selected_item do
+ selected_item = payload[socket.assigns.selected_item.name]
+ assign(socket, :selected_item, selected_item)
+ else
+ socket
+ end
+
+ {:noreply, assign(socket, %{items_all: payload, items: searched_and_filtered_items})}
+
:stdlog ->
# Logger.info("ServiceLive: Stdlog: #{inspect(payload)}")
@@ -171,20 +191,15 @@ defmodule FreediveWeb.ServiceLive.Components do
def service_header(assigns) do
~H"""
<.panel_block>
- <.icon_raw for={@selected_item.icon} color="auto" size="3rem" aria-hidden="true" />
+ <.icon_raw for={@selected_item.icon} color="auto" size="2.5rem" aria-hidden="true" />
<.title is-4>
<%= @selected_item.name %>
- <%= if @selected_item.running do %>
- <.icon for="circle-play" color="lightgreen" aria-hidden="true" />
- <% else %>
- <.icon for="circle-stop" color="gray" aria-hidden="true" />
- <% end %>
- <%= if @selected_item.enabled do %>
- <.icon for="circle-check" color="lightgreen" aria-hidden="true" />
- <% else %>
- <.icon for="circle-x" color="gray" aria-hidden="true" />
- <% end %>
+
+
+ <.icon_running item={@selected_item} size="1.2rem" />
+ <.icon_enabled item={@selected_item} size="1.2rem" />
+
<.subtitle>
<%= @selected_item.description %>
@@ -201,23 +216,14 @@ defmodule FreediveWeb.ServiceLive.Components do
phx-click="tap"
phx-value-name={@item.name}
>
-
<.icon_raw for={@item.icon} color="auto" size="1.5rem" aria-hidden="true" />
<%= @item.name %>
- <%= if @item.running do %>
- <.icon for="circle-play" size="1rem" color="lightgreen" aria-hidden="true" />
- <% else %>
- <.icon for="circle-stop" size="1rem" color="gray" aria-hidden="true" />
- <% end %>
- <%= if @item.enabled do %>
- <.icon for="circle-check" size="1rem" color="lightgreen" aria-hidden="true" />
- <% else %>
- <.icon for="circle-x" size="1rem" color="gray" aria-hidden="true" />
- <% end %>
+ <.icon_running item={@item} size="1rem" />
+ <.icon_enabled item={@item} size="1rem" />
"""
end
@@ -298,4 +304,24 @@ defmodule FreediveWeb.ServiceLive.Components do
<% end %>
"""
end
+
+ def icon_running(assigns) do
+ ~H"""
+ <%= if @item.running do %>
+ <.icon for="running" title="Running" size={@size} color="auto" aria-hidden="true" />
+ <% else %>
+ <.icon for="stopped" title="Stopped" size={@size} color="auto" aria-hidden="true" />
+ <% end %>
+ """
+ end
+
+ def icon_enabled(assigns) do
+ ~H"""
+ <%= if @item.enabled do %>
+ <.icon for="enabled" title="Enabled" size={@size} color="auto" aria-hidden="true" />
+ <% else %>
+ <.icon for="disabled" title="Disabled" size={@size} color="auto" aria-hidden="true" />
+ <% end %>
+ """
+ end
end
diff --git a/lib/liliform/icon.ex b/lib/liliform/icon.ex
index 770025b..f39c2a4 100644
--- a/lib/liliform/icon.ex
+++ b/lib/liliform/icon.ex
@@ -50,6 +50,7 @@ defmodule Liliform.Icon do
<.icon for="info" size="2rem" />
"""
attr :for, :string, required: true, doc: "icon name"
+ attr :title, :string, default: nil, doc: "icon title"
attr :size, :string, default: nil, doc: "size of icon"
attr :color, :string, default: nil, doc: "color of icon"
attr :class, :string, default: "", doc: "additional classes"
@@ -72,7 +73,14 @@ defmodule Liliform.Icon do
~H"""
- <.icon_svg for={@for} height={@size} width={@size} {icon_color(assigns)} />
+ <.icon_svg
+ for={@for}
+ title={@title}
+ height={@size}
+ width={@size}
+ {icon_color(assigns)}
+ {@rest}
+ />
<%= if @inner_block != [] do %>
@@ -87,6 +95,7 @@ defmodule Liliform.Icon do
Renders an icon without the icon-text wrapper.
"""
attr :for, :string, required: true, doc: "icon name"
+ attr :title, :string, default: nil, doc: "icon title"
attr :size, :string, default: nil, doc: "size of icon"
attr :color, :string, default: nil, doc: "color of icon"
attr :rest, :global
@@ -97,7 +106,7 @@ defmodule Liliform.Icon do
|> set_bulma_classes()
~H"""
- <.icon_svg for={@for} height={@size} width={@size} {icon_color(assigns)} {@rest} />
+ <.icon_svg for={@for} title={@title} height={@size} width={@size} {icon_color(assigns)} {@rest} />
"""
end
@@ -112,38 +121,35 @@ defmodule Liliform.Icon do
defp icon_color(assigns) do
if Features.enabled?(:colorhash) do
- color =
- case assigns.color do
- nil -> ""
- "auto" -> Colorhash.hsl(assigns.for)
- color -> color
- end
-
- auto_color =
- case assigns.for do
- "alert" -> [class: "has-text-danger"]
- "info" -> [class: "has-text-info"]
- "success" -> [class: "has-text-success"]
- "warning" -> [class: "has-text-warning"]
- "error" -> [class: "has-text-danger"]
- "all" -> [color: "magenta"]
- "compute" -> [color: "blue"]
- "storage" -> [color: "green"]
- "network" -> [color: "orange"]
- "system" -> [color: "purple"]
- "account" -> [color: "darkblue"]
- _ -> [color: color]
- end
-
- case color do
- "auto" ->
- auto_color
-
- "" ->
+ case assigns.color do
+ nil ->
[]
- _ ->
- [color: color]
+ clr ->
+ case String.downcase(clr) do
+ "auto" ->
+ case String.downcase(assigns.for) do
+ "alert" -> [class: "has-text-danger"]
+ "info" -> [class: "has-text-info"]
+ "success" -> [class: "has-text-success"]
+ "warning" -> [class: "has-text-warning"]
+ "error" -> [class: "has-text-danger"]
+ "all" -> [color: "magenta"]
+ "compute" -> [color: "blue"]
+ "storage" -> [color: "green"]
+ "network" -> [color: "orange"]
+ "system" -> [color: "purple"]
+ "account" -> [color: "darkblue"]
+ "running" -> [color: "lime"]
+ "stopped" -> [color: "gray"]
+ "enabled" -> [color: "blue"]
+ "disabled" -> [color: "gray"]
+ _ -> [color: Colorhash.hsl(assigns.for)]
+ end
+
+ _ ->
+ [color: assigns.color]
+ end
end
else
[class: "has-text-dark"]
@@ -170,7 +176,9 @@ defmodule Liliform.Icon do
"ntpdate" -> :clock
"httpd" -> :globe
"running" -> :circle_play
+ "stopped" -> :circle_stop
"enabled" -> :circle_check
+ "disabled" -> :circle_x
lucide_name -> String.to_atom(lucide_name)
end
end
diff --git a/lib/liliform/page.ex b/lib/liliform/page.ex
index 7275d6e..43698e1 100644
--- a/lib/liliform/page.ex
+++ b/lib/liliform/page.ex
@@ -53,7 +53,7 @@ defmodule Liliform.Page do
phx-value-key={filter.key}
>
<.icon_raw
- for={filter.icon}
+ for={filter.title}
size="2rem"
color={if filter.active, do: "gray", else: "auto"}
/>
diff --git a/mix.exs b/mix.exs
index 3b76755..e53489f 100644
--- a/mix.exs
+++ b/mix.exs
@@ -19,7 +19,7 @@ defmodule Freedive.MixProject do
defp freebsd_pkg do
[
- service_commands: ["init", "account_register", "password_reset"],
+ service_commands: ["init", "account_register", "password_reset"]
]
end
@@ -73,7 +73,8 @@ defmodule Freedive.MixProject do
{:lucide_icons, "~> 1.1"},
{:phx_component_helpers, "~> 1.4"},
{:mix_freebsd_pkg, github: "hiway/mix_freebsd_pkg", runtime: Mix.env() == :dev},
- {:phx_config_util, "~> 0.1.0"}
+ {:phx_config_util, "~> 0.1.0"},
+ {:file_system, "~> 1.0"}
]
end