feat: remove organization slug from sites and devices URLs
- Created new on_mount hook :load_default_organization that automatically loads user's first organization - Moved sites and devices routes to root path (/ sites, /devices) instead of /orgs/:org_slug - Updated all navigation links and route references throughout the app - Dashboard, alerts, and agents still use org-specific routes (/orgs/:org_slug) - Users can still switch organizations via org selector for other pages
This commit is contained in:
parent
3e797ae715
commit
9c2f08317f
16 changed files with 129 additions and 87 deletions
|
|
@ -150,13 +150,13 @@ defmodule ToweropsWeb.Layouts do
|
|||
Dashboard
|
||||
</.nav_link>
|
||||
<.nav_link
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/sites"}
|
||||
navigate={~p"/sites"}
|
||||
active={@active_page == "sites"}
|
||||
>
|
||||
Sites
|
||||
</.nav_link>
|
||||
<.nav_link
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/devices"}
|
||||
navigate={~p"/devices"}
|
||||
active={@active_page == "devices"}
|
||||
>
|
||||
Devices
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@
|
|||
<div class="divide-y divide-zinc-200 dark:divide-zinc-800">
|
||||
<%= for device <- @polling_targets do %>
|
||||
<.link
|
||||
navigate={~p"/orgs/#{@organization.slug}/devices/#{device.id}"}
|
||||
navigate={~p"/devices/#{device.id}"}
|
||||
class="block hover:bg-zinc-50 dark:hover:bg-zinc-800 transition-colors"
|
||||
>
|
||||
<div class="p-6">
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@
|
|||
|
||||
<h3 class="mt-3 font-semibold text-zinc-900 dark:text-zinc-100">
|
||||
<.link
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/devices/#{alert.device.id}"}
|
||||
navigate={~p"/devices/#{alert.device.id}"}
|
||||
class="text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
{alert.device.name}
|
||||
|
|
@ -130,9 +130,7 @@
|
|||
<div>
|
||||
<strong class="font-medium">Site:</strong>
|
||||
<.link
|
||||
navigate={
|
||||
~p"/orgs/#{@current_organization.slug}/sites/#{alert.device.site.id}"
|
||||
}
|
||||
navigate={~p"/sites/#{alert.device.site.id}"}
|
||||
class="text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
{alert.device.site.name}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="mt-8">
|
||||
<.button navigate={~p"/orgs/#{@current_organization.slug}/sites/new"} variant="primary">
|
||||
<.button navigate={~p"/sites/new"} variant="primary">
|
||||
<.icon name="hero-plus" class="h-5 w-5" /> Create Your First Site
|
||||
</.button>
|
||||
</div>
|
||||
|
|
@ -70,7 +70,7 @@
|
|||
<% else %>
|
||||
<div class="mt-8 grid gap-6 md:grid-cols-2 lg:grid-cols-4">
|
||||
<.link
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/sites"}
|
||||
navigate={~p"/sites"}
|
||||
class="rounded-lg border border-zinc-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md dark:border-zinc-800 dark:bg-zinc-900"
|
||||
>
|
||||
<h3 class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Sites</h3>
|
||||
|
|
@ -79,7 +79,7 @@
|
|||
</.link>
|
||||
|
||||
<.link
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/devices"}
|
||||
navigate={~p"/devices"}
|
||||
class="rounded-lg border border-zinc-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md dark:border-zinc-800 dark:bg-zinc-900"
|
||||
>
|
||||
<h3 class="text-sm font-medium text-zinc-500 dark:text-zinc-400">Device</h3>
|
||||
|
|
@ -155,7 +155,7 @@
|
|||
<div class="flex-1 min-w-0">
|
||||
<h3 class="font-semibold text-zinc-900 dark:text-zinc-100">
|
||||
<.link
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/devices/#{alert.device.id}"}
|
||||
navigate={~p"/devices/#{alert.device.id}"}
|
||||
class="hover:text-blue-600 hover:underline dark:hover:text-blue-400"
|
||||
>
|
||||
{alert.device.name}
|
||||
|
|
@ -182,14 +182,14 @@
|
|||
<h2 class="text-xl font-semibold mb-4 text-zinc-900 dark:text-zinc-100">Quick Actions</h2>
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<.link
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/sites"}
|
||||
navigate={~p"/sites"}
|
||||
class="inline-flex items-center gap-2 rounded-lg bg-blue-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 dark:bg-blue-500 dark:hover:bg-blue-600"
|
||||
>
|
||||
<.icon name="hero-building-office" class="h-5 w-5" />
|
||||
<span>Manage Sites</span>
|
||||
</.link>
|
||||
<.link
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/devices"}
|
||||
navigate={~p"/devices"}
|
||||
class="inline-flex items-center gap-2 rounded-lg bg-blue-600 px-4 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 dark:bg-blue-500 dark:hover:bg-blue-600"
|
||||
>
|
||||
<.icon name="hero-server" class="h-5 w-5" />
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ defmodule ToweropsWeb.DeviceLive.Form do
|
|||
{:ok,
|
||||
socket
|
||||
|> put_flash(:info, "Please create a site before adding a device.")
|
||||
|> push_navigate(to: ~p"/orgs/#{organization.slug}/sites/new")}
|
||||
|> push_navigate(to: ~p"/sites/new")}
|
||||
else
|
||||
{:ok,
|
||||
socket
|
||||
|
|
@ -163,7 +163,7 @@ defmodule ToweropsWeb.DeviceLive.Form do
|
|||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:info, "Device deleted successfully")
|
||||
|> push_navigate(to: ~p"/orgs/#{socket.assigns.organization.slug}/devices")}
|
||||
|> push_navigate(to: ~p"/devices")}
|
||||
|
||||
{:error, _} ->
|
||||
{:noreply, put_flash(socket, :error, "Unable to delete device")}
|
||||
|
|
@ -203,7 +203,7 @@ defmodule ToweropsWeb.DeviceLive.Form do
|
|||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:info, "Discovery started...")
|
||||
|> push_navigate(to: ~p"/orgs/#{socket.assigns.organization.slug}/devices/#{device.id}")}
|
||||
|> push_navigate(to: ~p"/devices/#{device.id}")}
|
||||
else
|
||||
{:noreply, put_flash(socket, :error, "SNMP is not enabled for this device")}
|
||||
end
|
||||
|
|
@ -271,7 +271,7 @@ defmodule ToweropsWeb.DeviceLive.Form do
|
|||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:info, flash_message)
|
||||
|> push_navigate(to: ~p"/orgs/#{socket.assigns.organization.slug}/devices/#{device.id}")}
|
||||
|> push_navigate(to: ~p"/devices/#{device.id}")}
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
{:noreply, assign(socket, :form, to_form(changeset))}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
<.link
|
||||
navigate={
|
||||
if @live_action == :edit,
|
||||
do: ~p"/orgs/#{@organization.slug}/devices/#{@device.id}",
|
||||
else: ~p"/orgs/#{@organization.slug}/devices"
|
||||
do: ~p"/devices/#{@device.id}",
|
||||
else: ~p"/devices"
|
||||
}
|
||||
class="inline-flex items-center gap-1 text-sm text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
|
||||
>
|
||||
|
|
@ -240,7 +240,7 @@
|
|||
|
||||
<div class="flex gap-3 mt-6">
|
||||
<.button phx-disable-with="Saving..." variant="primary">Save Device</.button>
|
||||
<.button navigate={~p"/orgs/#{@organization.slug}/devices"}>Cancel</.button>
|
||||
<.button navigate={~p"/devices"}>Cancel</.button>
|
||||
</div>
|
||||
</.form>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<:actions>
|
||||
<.button
|
||||
:if={@has_sites}
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/devices/new"}
|
||||
navigate={~p"/devices/new"}
|
||||
variant="primary"
|
||||
>
|
||||
<.icon name="hero-plus" class="h-5 w-5" /> New Device
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
Sites help you organize your devices by physical location.
|
||||
</p>
|
||||
<div class="mt-6">
|
||||
<.button navigate={~p"/orgs/#{@current_organization.slug}/sites/new"} variant="primary">
|
||||
<.button navigate={~p"/sites/new"} variant="primary">
|
||||
<.icon name="hero-plus" class="h-5 w-5" /> Create Your First Site
|
||||
</.button>
|
||||
</div>
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
</p>
|
||||
<div class="mt-6">
|
||||
<.button
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/devices/new"}
|
||||
navigate={~p"/devices/new"}
|
||||
variant="primary"
|
||||
>
|
||||
<.icon name="hero-plus" class="h-5 w-5" /> New Device
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
rows={@device}
|
||||
row_click={
|
||||
fn eq ->
|
||||
JS.navigate(~p"/orgs/#{@current_organization.slug}/devices/#{eq.id}")
|
||||
JS.navigate(~p"/devices/#{eq.id}")
|
||||
end
|
||||
}
|
||||
>
|
||||
|
|
@ -75,7 +75,7 @@
|
|||
</:col>
|
||||
<:col :let={eq} label="Site">
|
||||
<.link
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/sites/#{eq.site.id}"}
|
||||
navigate={~p"/sites/#{eq.site.id}"}
|
||||
class="text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
{eq.site.name}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<ol class="inline-flex items-center space-x-1 text-sm text-zinc-600 dark:text-zinc-400">
|
||||
<li class="inline-flex items-center">
|
||||
<.link
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/sites/#{@device.site.id}"}
|
||||
navigate={~p"/sites/#{@device.site.id}"}
|
||||
class="hover:text-zinc-900 dark:hover:text-zinc-200"
|
||||
>
|
||||
{@device.site.name}
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
<p class="text-sm text-zinc-600 dark:text-zinc-400 font-mono">{@device.ip_address}</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<.button navigate={~p"/orgs/#{@current_organization.slug}/devices/#{@device.id}/edit"}>
|
||||
<.button navigate={~p"/devices/#{@device.id}/edit"}>
|
||||
<.icon name="hero-pencil" class="h-4 w-4" /> Edit
|
||||
</.button>
|
||||
</div>
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
<div class="border-b border-zinc-200 dark:border-zinc-700">
|
||||
<nav class="-mb-px flex space-x-8">
|
||||
<.link
|
||||
patch={~p"/orgs/#{@current_organization.slug}/devices/#{@device.id}?tab=overview"}
|
||||
patch={~p"/devices/#{@device.id}?tab=overview"}
|
||||
class={[
|
||||
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
|
||||
if @active_tab == "overview" do
|
||||
|
|
@ -56,7 +56,7 @@
|
|||
|
||||
<%= if @snmp_device do %>
|
||||
<.link
|
||||
patch={~p"/orgs/#{@current_organization.slug}/devices/#{@device.id}?tab=ports"}
|
||||
patch={~p"/devices/#{@device.id}?tab=ports"}
|
||||
class={[
|
||||
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
|
||||
if @active_tab == "ports" do
|
||||
|
|
@ -71,7 +71,7 @@
|
|||
<% end %>
|
||||
|
||||
<.link
|
||||
patch={~p"/orgs/#{@current_organization.slug}/devices/#{@device.id}?tab=neighbors"}
|
||||
patch={~p"/devices/#{@device.id}?tab=neighbors"}
|
||||
class={[
|
||||
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
|
||||
if @active_tab == "neighbors" do
|
||||
|
|
@ -85,7 +85,7 @@
|
|||
</.link>
|
||||
|
||||
<.link
|
||||
patch={~p"/orgs/#{@current_organization.slug}/devices/#{@device.id}?tab=logs"}
|
||||
patch={~p"/devices/#{@device.id}?tab=logs"}
|
||||
class={[
|
||||
"whitespace-nowrap py-4 px-1 border-b-2 font-medium text-sm",
|
||||
if @active_tab == "logs" do
|
||||
|
|
@ -216,9 +216,7 @@
|
|||
<%= if @traffic_chart_data do %>
|
||||
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
|
||||
<.link
|
||||
navigate={
|
||||
~p"/orgs/#{@current_organization.slug}/devices/#{@device.id}/graph/traffic"
|
||||
}
|
||||
navigate={~p"/devices/#{@device.id}/graph/traffic"}
|
||||
class="block px-4 py-3 border-b border-zinc-200 dark:border-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-750 transition-colors"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
|
|
@ -247,9 +245,7 @@
|
|||
<%= if @latency_chart_data do %>
|
||||
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
|
||||
<.link
|
||||
navigate={
|
||||
~p"/orgs/#{@current_organization.slug}/devices/#{@device.id}/graph/latency"
|
||||
}
|
||||
navigate={~p"/devices/#{@device.id}/graph/latency"}
|
||||
class="block px-4 py-3 border-b border-zinc-200 dark:border-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-750 transition-colors"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
|
|
@ -280,9 +276,7 @@
|
|||
<%= if @cpu_chart_data do %>
|
||||
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
|
||||
<.link
|
||||
navigate={
|
||||
~p"/orgs/#{@current_organization.slug}/devices/#{@device.id}/graph/processors"
|
||||
}
|
||||
navigate={~p"/devices/#{@device.id}/graph/processors"}
|
||||
class="block px-4 py-3 border-b border-zinc-200 dark:border-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-750 transition-colors"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
|
|
@ -308,9 +302,7 @@
|
|||
<%= if @memory_chart_data do %>
|
||||
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700">
|
||||
<.link
|
||||
navigate={
|
||||
~p"/orgs/#{@current_organization.slug}/devices/#{@device.id}/graph/memory"
|
||||
}
|
||||
navigate={~p"/devices/#{@device.id}/graph/memory"}
|
||||
class="block px-4 py-3 border-b border-zinc-200 dark:border-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-750 transition-colors"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
|
|
@ -346,9 +338,7 @@
|
|||
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
|
||||
<dt class="text-sm text-zinc-600 dark:text-zinc-400">
|
||||
<.link
|
||||
navigate={
|
||||
~p"/orgs/#{@current_organization.slug}/devices/#{@device.id}/graph/storage"
|
||||
}
|
||||
navigate={~p"/devices/#{@device.id}/graph/storage"}
|
||||
class="hover:text-blue-600 dark:hover:text-blue-400 hover:underline"
|
||||
>
|
||||
{sensor.sensor_descr}
|
||||
|
|
@ -385,9 +375,7 @@
|
|||
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
|
||||
<dt class="text-sm text-zinc-600 dark:text-zinc-400">
|
||||
<.link
|
||||
navigate={
|
||||
~p"/orgs/#{@current_organization.slug}/devices/#{@device.id}/graph/temperature"
|
||||
}
|
||||
navigate={~p"/devices/#{@device.id}/graph/temperature"}
|
||||
class="hover:text-blue-600 dark:hover:text-blue-400 hover:underline"
|
||||
>
|
||||
{sensor.sensor_descr}
|
||||
|
|
@ -422,9 +410,7 @@
|
|||
<div class="flex justify-between py-1.5 border-b border-zinc-100 dark:border-zinc-800">
|
||||
<dt class="text-sm text-zinc-600 dark:text-zinc-400">
|
||||
<.link
|
||||
navigate={
|
||||
~p"/orgs/#{@current_organization.slug}/devices/#{@device.id}/graph/voltage"
|
||||
}
|
||||
navigate={~p"/devices/#{@device.id}/graph/voltage"}
|
||||
class="hover:text-blue-600 dark:hover:text-blue-400 hover:underline"
|
||||
>
|
||||
{sensor.sensor_descr}
|
||||
|
|
@ -482,7 +468,7 @@
|
|||
<td class="px-4 py-3">
|
||||
<.link
|
||||
navigate={
|
||||
~p"/orgs/#{@current_organization.slug}/devices/#{@device.id}/graph/traffic?interface_id=#{interface.id}"
|
||||
~p"/devices/#{@device.id}/graph/traffic?interface_id=#{interface.id}"
|
||||
}
|
||||
class="hover:text-blue-600 dark:hover:text-blue-400"
|
||||
>
|
||||
|
|
@ -569,9 +555,7 @@
|
|||
<td class="px-4 py-3">
|
||||
<%= if neighbor.matched_device do %>
|
||||
<.link
|
||||
navigate={
|
||||
~p"/orgs/#{@current_organization.slug}/devices/#{neighbor.matched_device.id}"
|
||||
}
|
||||
navigate={~p"/devices/#{neighbor.matched_device.id}"}
|
||||
class="font-medium text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
{neighbor.matched_device.name}
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ defmodule ToweropsWeb.GraphLive.Show do
|
|||
|
||||
{:noreply,
|
||||
push_patch(socket,
|
||||
to:
|
||||
~p"/orgs/#{socket.assigns.current_organization.slug}/devices/#{socket.assigns.device_id}/graph/#{socket.assigns.sensor_type}?#{params}"
|
||||
to: ~p"/devices/#{socket.assigns.device_id}/graph/#{socket.assigns.sensor_type}?#{params}"
|
||||
)}
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
<div class="flex items-center justify-between mb-6">
|
||||
<div class="flex items-center gap-4">
|
||||
<.link
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/devices/#{@device_id}"}
|
||||
navigate={~p"/devices/#{@device_id}"}
|
||||
class="text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
|
||||
>
|
||||
<.icon name="hero-arrow-left" class="h-5 w-5" />
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ defmodule ToweropsWeb.SiteLive.Form do
|
|||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:info, "Site deleted successfully")
|
||||
|> push_navigate(to: ~p"/orgs/#{socket.assigns.organization.slug}/sites")}
|
||||
|> push_navigate(to: ~p"/sites")}
|
||||
|
||||
{:error, _} ->
|
||||
{:noreply, put_flash(socket, :error, "Unable to delete site")}
|
||||
|
|
@ -115,7 +115,7 @@ defmodule ToweropsWeb.SiteLive.Form do
|
|||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:info, "Site created successfully! Now add your first device.")
|
||||
|> push_navigate(to: ~p"/orgs/#{socket.assigns.organization.slug}/sites/#{site.id}")}
|
||||
|> push_navigate(to: ~p"/sites/#{site.id}")}
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
{:noreply, assign(socket, :form, to_form(changeset))}
|
||||
|
|
@ -128,7 +128,7 @@ defmodule ToweropsWeb.SiteLive.Form do
|
|||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:info, "Site updated successfully")
|
||||
|> push_navigate(to: ~p"/orgs/#{socket.assigns.organization.slug}/sites")}
|
||||
|> push_navigate(to: ~p"/sites")}
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
{:noreply, assign(socket, :form, to_form(changeset))}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
<.link
|
||||
navigate={
|
||||
if @live_action == :edit,
|
||||
do: ~p"/orgs/#{@current_organization.slug}/sites/#{@site.id}",
|
||||
else: ~p"/orgs/#{@current_organization.slug}/sites"
|
||||
do: ~p"/sites/#{@site.id}",
|
||||
else: ~p"/sites"
|
||||
}
|
||||
class="inline-flex items-center gap-1 text-sm text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
|
||||
>
|
||||
|
|
@ -181,7 +181,7 @@
|
|||
|
||||
<div class="flex gap-3 mt-6">
|
||||
<.button phx-disable-with="Saving..." variant="primary">Save Site</.button>
|
||||
<.button navigate={~p"/orgs/#{@current_organization.slug}/sites"}>Cancel</.button>
|
||||
<.button navigate={~p"/sites"}>Cancel</.button>
|
||||
</div>
|
||||
</.form>
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
{@page_title}
|
||||
<:subtitle>Manage your site locations and hierarchy</:subtitle>
|
||||
<:actions>
|
||||
<.button navigate={~p"/orgs/#{@current_organization.slug}/sites/new"} variant="primary">
|
||||
<.button navigate={~p"/sites/new"} variant="primary">
|
||||
<.icon name="hero-plus" class="h-5 w-5" /> New Site
|
||||
</.button>
|
||||
</:actions>
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
Get started by creating your first site.
|
||||
</p>
|
||||
<div class="mt-6">
|
||||
<.button navigate={~p"/orgs/#{@current_organization.slug}/sites/new"} variant="primary">
|
||||
<.button navigate={~p"/sites/new"} variant="primary">
|
||||
<.icon name="hero-plus" class="h-5 w-5" /> New Site
|
||||
</.button>
|
||||
</div>
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
<.link
|
||||
:for={site <- @sites}
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/sites/#{site.id}"}
|
||||
navigate={~p"/sites/#{site.id}"}
|
||||
class="relative overflow-hidden rounded-lg border border-zinc-200 bg-white p-6 shadow-sm hover:shadow-md transition-shadow dark:border-zinc-800 dark:bg-zinc-900 cursor-pointer"
|
||||
>
|
||||
<h3 class="text-xl font-semibold text-zinc-900 dark:text-zinc-100">{site.name}</h3>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
{@page_title}
|
||||
<:subtitle>{@site.location}</:subtitle>
|
||||
<:actions>
|
||||
<.button navigate={~p"/orgs/#{@current_organization.slug}/sites/#{@site.id}/edit"}>
|
||||
<.button navigate={~p"/sites/#{@site.id}/edit"}>
|
||||
<.icon name="hero-pencil" class="h-4 w-4" /> Edit
|
||||
</.button>
|
||||
</:actions>
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
<dt class="text-sm font-medium text-zinc-600 dark:text-zinc-400">Parent Site</dt>
|
||||
<dd class="mt-1">
|
||||
<.link
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/sites/#{@site.parent_site.id}"}
|
||||
navigate={~p"/sites/#{@site.parent_site.id}"}
|
||||
class="text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
{@site.parent_site.name}
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
<ul class="space-y-2">
|
||||
<li :for={child <- @site.child_sites}>
|
||||
<.link
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/sites/#{child.id}"}
|
||||
navigate={~p"/sites/#{child.id}"}
|
||||
class="text-sm text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
|
||||
>
|
||||
{child.name}
|
||||
|
|
@ -67,7 +67,7 @@
|
|||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 class="text-lg font-semibold text-zinc-900 dark:text-zinc-100">Device</h3>
|
||||
<.button
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/devices/new?site_id=#{@site.id}"}
|
||||
navigate={~p"/devices/new?site_id=#{@site.id}"}
|
||||
variant="primary"
|
||||
>
|
||||
<.icon name="hero-plus" class="h-4 w-4" /> Add Device
|
||||
|
|
@ -88,7 +88,7 @@
|
|||
</p>
|
||||
<div class="mt-6">
|
||||
<.button
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/devices/new?site_id=#{@site.id}"}
|
||||
navigate={~p"/devices/new?site_id=#{@site.id}"}
|
||||
variant="primary"
|
||||
>
|
||||
<.icon name="hero-plus" class="h-5 w-5" /> Add Device
|
||||
|
|
@ -99,7 +99,7 @@
|
|||
<div class="space-y-3">
|
||||
<.link
|
||||
:for={eq <- @device}
|
||||
navigate={~p"/orgs/#{@current_organization.slug}/devices/#{eq.id}"}
|
||||
navigate={~p"/devices/#{eq.id}"}
|
||||
class="flex items-center justify-between rounded-lg border border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-900 hover:border-zinc-300 dark:hover:border-zinc-700 hover:bg-zinc-50 dark:hover:bg-zinc-800 transition-colors cursor-pointer"
|
||||
>
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -198,6 +198,24 @@ defmodule ToweropsWeb.Router do
|
|||
live "/", DashboardLive, :index
|
||||
live "/settings", Org.SettingsLive, :index
|
||||
|
||||
# Alert routes
|
||||
live "/alerts", AlertLive.Index, :index
|
||||
|
||||
# Agent routes
|
||||
live "/agents", AgentLive.Index, :index
|
||||
live "/agents/:id/edit", AgentLive.Edit, :edit
|
||||
live "/agents/:id", AgentLive.Show, :show
|
||||
end
|
||||
end
|
||||
|
||||
live_session :require_authenticated_user_with_default_org,
|
||||
on_mount: [
|
||||
{ToweropsWeb.UserAuth, :require_authenticated_user},
|
||||
{ToweropsWeb.UserAuth, :load_default_organization}
|
||||
] do
|
||||
scope "/", ToweropsWeb do
|
||||
pipe_through [:browser, :require_authenticated_user]
|
||||
|
||||
# Site routes
|
||||
live "/sites", SiteLive.Index, :index
|
||||
live "/sites/new", SiteLive.Form, :new
|
||||
|
|
@ -210,14 +228,6 @@ defmodule ToweropsWeb.Router do
|
|||
live "/devices/:id", DeviceLive.Show, :show
|
||||
live "/devices/:id/edit", DeviceLive.Form, :edit
|
||||
live "/devices/:id/graph/:sensor_type", GraphLive.Show, :show
|
||||
|
||||
# Alert routes
|
||||
live "/alerts", AlertLive.Index, :index
|
||||
|
||||
# Agent routes
|
||||
live "/agents", AgentLive.Index, :index
|
||||
live "/agents/:id/edit", AgentLive.Edit, :edit
|
||||
live "/agents/:id", AgentLive.Show, :show
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -247,9 +247,9 @@ defmodule ToweropsWeb.UserAuth do
|
|||
if user do
|
||||
# Get user's organizations (ordered by most recently joined first)
|
||||
case Towerops.Organizations.list_user_organizations(user.id) do
|
||||
[first_org | _] ->
|
||||
# device page
|
||||
~p"/orgs/#{first_org.slug}/devices"
|
||||
[_first_org | _] ->
|
||||
# Devices page (no longer needs org slug)
|
||||
~p"/devices"
|
||||
|
||||
[] ->
|
||||
# No organizations yet, go to org list
|
||||
|
|
@ -428,6 +428,57 @@ defmodule ToweropsWeb.UserAuth do
|
|||
{:cont, socket}
|
||||
end
|
||||
|
||||
def on_mount(:load_default_organization, _params, session, socket) do
|
||||
user = socket.assigns.current_scope && socket.assigns.current_scope.user
|
||||
|
||||
if user do
|
||||
# Try to get organization from session, otherwise use first organization
|
||||
org_id = session["current_organization_id"]
|
||||
|
||||
organization =
|
||||
if org_id do
|
||||
try do
|
||||
Towerops.Organizations.get_organization!(org_id)
|
||||
rescue
|
||||
Ecto.NoResultsError -> nil
|
||||
end
|
||||
else
|
||||
# Get first organization user has access to
|
||||
case Towerops.Organizations.list_user_organizations(user.id) do
|
||||
[first_org | _] -> first_org
|
||||
[] -> nil
|
||||
end
|
||||
end
|
||||
|
||||
if organization do
|
||||
membership = Towerops.Organizations.get_membership(organization.id, user.id)
|
||||
|
||||
if membership do
|
||||
{:cont,
|
||||
socket
|
||||
|> Phoenix.Component.assign(:current_organization, organization)
|
||||
|> Phoenix.Component.assign(:current_membership, membership)}
|
||||
else
|
||||
socket =
|
||||
socket
|
||||
|> LiveView.put_flash(:error, "You don't have access to any organizations.")
|
||||
|> LiveView.redirect(to: ~p"/orgs")
|
||||
|
||||
{:halt, socket}
|
||||
end
|
||||
else
|
||||
socket =
|
||||
socket
|
||||
|> LiveView.put_flash(:error, "Please select an organization.")
|
||||
|> LiveView.redirect(to: ~p"/orgs")
|
||||
|
||||
{:halt, socket}
|
||||
end
|
||||
else
|
||||
{:cont, socket}
|
||||
end
|
||||
end
|
||||
|
||||
def on_mount(:require_superuser, _params, session, socket) do
|
||||
socket = mount_current_scope(socket, session)
|
||||
user = socket.assigns.current_scope && socket.assigns.current_scope.user
|
||||
|
|
@ -596,10 +647,10 @@ defmodule ToweropsWeb.UserAuth do
|
|||
ip_address: ip
|
||||
})
|
||||
|
||||
# device page
|
||||
# Devices page
|
||||
redirect_path =
|
||||
case Towerops.Organizations.list_user_organizations(superuser.id) do
|
||||
[first_org | _] -> ~p"/orgs/#{first_org.slug}/devices"
|
||||
[_first_org | _] -> ~p"/devices"
|
||||
[] -> ~p"/orgs"
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue