cleanup forms
This commit is contained in:
parent
5d5116681a
commit
02413d5cfd
2 changed files with 115 additions and 272 deletions
|
|
@ -38,25 +38,17 @@ defmodule ToweropsWeb.Org.SettingsLive do
|
|||
{:noreply, assign(socket, :form, to_form(changeset))}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("toggle_mikrotik", _params, socket) do
|
||||
# credo:disable-for-next-line Credo.Check.Design.AliasUsage
|
||||
current_value = Phoenix.HTML.Form.input_value(socket.assigns.form, :mikrotik_enabled)
|
||||
new_value = !current_value
|
||||
|
||||
changeset = Organizations.change_organization(socket.assigns.organization, %{"mikrotik_enabled" => new_value})
|
||||
|
||||
{:noreply, assign(socket, :form, to_form(changeset))}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_event("save", %{"organization" => org_params}, socket) do
|
||||
case Organizations.update_organization(socket.assigns.organization, org_params) do
|
||||
{:ok, organization} ->
|
||||
changeset = Organizations.change_organization(organization)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|> put_flash(:info, "Organization settings updated successfully")
|
||||
|> push_navigate(to: ~p"/orgs/#{organization.slug}")}
|
||||
|> put_flash(:info, "Settings saved successfully")
|
||||
|> assign(:organization, organization)
|
||||
|> assign(:form, to_form(changeset))}
|
||||
|
||||
{:error, %Ecto.Changeset{} = changeset} ->
|
||||
{:noreply, assign(socket, :form, to_form(changeset))}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
<.form
|
||||
for={@form}
|
||||
id="organization-form"
|
||||
phx-change="validate"
|
||||
phx-submit="save"
|
||||
data-1p-ignore
|
||||
data-form-type="other"
|
||||
|
|
@ -39,26 +40,12 @@
|
|||
</div>
|
||||
|
||||
<div class="md:col-span-2">
|
||||
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:max-w-xl sm:grid-cols-6">
|
||||
<div class="col-span-full">
|
||||
<label
|
||||
for="organization_name"
|
||||
class="block text-sm/6 font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
Organization Name
|
||||
</label>
|
||||
<div class="mt-2">
|
||||
<input
|
||||
type="text"
|
||||
name={@form[:name].name}
|
||||
id="organization_name"
|
||||
value={@form[:name].value}
|
||||
required
|
||||
class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:outline-white/10 dark:placeholder:text-gray-500 dark:focus:outline-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<.input
|
||||
field={@form[:name]}
|
||||
type="text"
|
||||
label="Organization Name"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -78,62 +65,20 @@
|
|||
</div>
|
||||
|
||||
<div class="md:col-span-2">
|
||||
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:max-w-xl sm:grid-cols-6">
|
||||
<div class="col-span-full">
|
||||
<label
|
||||
for="snmp_version"
|
||||
class="block text-sm/6 font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
SNMP Version
|
||||
</label>
|
||||
<div class="mt-2 grid grid-cols-1">
|
||||
<select
|
||||
name={@form[:snmp_version].name}
|
||||
id="snmp_version"
|
||||
class="col-start-1 row-start-1 w-full appearance-none rounded-md bg-white py-1.5 pr-8 pl-3 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:outline-white/10 dark:*:bg-gray-800 dark:focus:outline-indigo-500"
|
||||
>
|
||||
<option value="">Select SNMP version</option>
|
||||
<option value="1" selected={@form[:snmp_version].value == "1"}>SNMP v1</option>
|
||||
<option value="2c" selected={@form[:snmp_version].value == "2c"}>
|
||||
SNMP v2c
|
||||
</option>
|
||||
<option value="3" selected={@form[:snmp_version].value == "3"}>SNMP v3</option>
|
||||
</select>
|
||||
<svg
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
data-slot="icon"
|
||||
aria-hidden="true"
|
||||
class="pointer-events-none col-start-1 row-start-1 mr-2 size-5 self-center justify-self-end text-gray-400 sm:size-4"
|
||||
>
|
||||
<path
|
||||
d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z"
|
||||
clip-rule="evenodd"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<.input
|
||||
field={@form[:snmp_version]}
|
||||
type="select"
|
||||
label="SNMP Version"
|
||||
prompt="Select SNMP version"
|
||||
options={[{"SNMP v1", "1"}, {"SNMP v2c", "2c"}, {"SNMP v3", "3"}]}
|
||||
/>
|
||||
|
||||
<div class="col-span-full">
|
||||
<label
|
||||
for="snmp_community"
|
||||
class="block text-sm/6 font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
SNMP Community String
|
||||
</label>
|
||||
<div class="mt-2">
|
||||
<input
|
||||
type="text"
|
||||
name={@form[:snmp_community].name}
|
||||
id="snmp_community"
|
||||
value={@form[:snmp_community].value}
|
||||
placeholder="e.g., public"
|
||||
class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:outline-white/10 dark:placeholder:text-gray-500 dark:focus:outline-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<.input
|
||||
field={@form[:snmp_community]}
|
||||
type="text"
|
||||
label="SNMP Community String"
|
||||
placeholder="e.g., public"
|
||||
/>
|
||||
|
||||
<%= if @organization.snmp_community do %>
|
||||
<div class="mt-6 rounded-md bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 p-4">
|
||||
|
|
@ -174,126 +119,67 @@
|
|||
</div>
|
||||
|
||||
<div class="md:col-span-2" phx-update="replace" id="mikrotik-config-section">
|
||||
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:max-w-xl sm:grid-cols-6">
|
||||
<div class="col-span-full">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
name={@form[:mikrotik_enabled].name}
|
||||
id="mikrotik_enabled"
|
||||
checked={@form[:mikrotik_enabled].value}
|
||||
phx-click="toggle_mikrotik"
|
||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600 dark:border-white/10 dark:bg-white/5 dark:focus:ring-indigo-500"
|
||||
/>
|
||||
<label
|
||||
for="mikrotik_enabled"
|
||||
class="text-sm/6 font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
Enable MikroTik API
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<.input
|
||||
field={@form[:mikrotik_enabled]}
|
||||
type="checkbox"
|
||||
label="Enable MikroTik API"
|
||||
/>
|
||||
|
||||
<div class={"col-span-full #{unless @form[:mikrotik_enabled].value, do: "hidden"}"}>
|
||||
<label
|
||||
for="mikrotik_api_user"
|
||||
class="block text-sm/6 font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
Username
|
||||
</label>
|
||||
<div class="mt-2">
|
||||
<input
|
||||
type="text"
|
||||
name="organization[mikrotik_username]"
|
||||
id="mikrotik_api_user"
|
||||
value={@form[:mikrotik_username].value}
|
||||
placeholder="e.g., admin"
|
||||
autocomplete="off"
|
||||
data-1p-ignore
|
||||
class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:outline-white/10 dark:placeholder:text-gray-500 dark:focus:outline-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class={"#{unless @form[:mikrotik_enabled].value, do: "hidden"}"}>
|
||||
<.input
|
||||
field={@form[:mikrotik_username]}
|
||||
type="text"
|
||||
label="Username"
|
||||
placeholder="e.g., admin"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class={"col-span-full #{unless @form[:mikrotik_enabled].value, do: "hidden"}"}>
|
||||
<label
|
||||
for="mikrotik_api_secret"
|
||||
class="block text-sm/6 font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
Password
|
||||
</label>
|
||||
<div class="mt-2">
|
||||
<input
|
||||
type="password"
|
||||
name="organization[mikrotik_password]"
|
||||
id="mikrotik_api_secret"
|
||||
value={@form[:mikrotik_password].value}
|
||||
placeholder="RouterOS API password"
|
||||
autocomplete="off"
|
||||
data-1p-ignore
|
||||
data-lpignore="true"
|
||||
class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:outline-white/10 dark:placeholder:text-gray-500 dark:focus:outline-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class={"#{unless @form[:mikrotik_enabled].value, do: "hidden"}"}>
|
||||
<.input
|
||||
field={@form[:mikrotik_password]}
|
||||
type="password"
|
||||
label="Password"
|
||||
placeholder="RouterOS API password"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class={"col-span-full #{unless @form[:mikrotik_enabled].value, do: "hidden"}"}>
|
||||
<label
|
||||
for="mikrotik_port"
|
||||
class="block text-sm/6 font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
API Port
|
||||
</label>
|
||||
<div class="mt-2">
|
||||
<input
|
||||
type="number"
|
||||
name={@form[:mikrotik_port].name}
|
||||
id="mikrotik_port"
|
||||
value={@form[:mikrotik_port].value}
|
||||
placeholder="8729"
|
||||
autocomplete="off"
|
||||
data-1p-ignore
|
||||
class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:outline-white/10 dark:placeholder:text-gray-500 dark:focus:outline-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class={"#{unless @form[:mikrotik_enabled].value, do: "hidden"}"}>
|
||||
<.input
|
||||
field={@form[:mikrotik_port]}
|
||||
type="number"
|
||||
label="API Port"
|
||||
placeholder="8729"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class={"col-span-full #{unless @form[:mikrotik_enabled].value, do: "hidden"}"}>
|
||||
<div class="flex items-center gap-x-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
name={@form[:mikrotik_use_ssl].name}
|
||||
id="mikrotik_use_ssl"
|
||||
checked={@form[:mikrotik_use_ssl].value}
|
||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600 dark:border-white/10 dark:bg-white/5 dark:focus:ring-indigo-500"
|
||||
/>
|
||||
<label
|
||||
for="mikrotik_use_ssl"
|
||||
class="text-sm/6 font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
Use SSL (API-SSL)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class={"#{unless @form[:mikrotik_enabled].value, do: "hidden"}"}>
|
||||
<.input
|
||||
field={@form[:mikrotik_use_ssl]}
|
||||
type="checkbox"
|
||||
label="Use SSL (API-SSL)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class={"col-span-full #{unless @form[:mikrotik_enabled].value, do: "hidden"} #{if @form[:mikrotik_use_ssl].value != false, do: "hidden"}"}>
|
||||
<div class="rounded-md bg-red-50 dark:bg-red-900/20 p-4">
|
||||
<p class="text-sm text-red-700 dark:text-red-300">
|
||||
<strong>Critical Security Warning:</strong>
|
||||
Plain API (port 8728) sends credentials unencrypted over the network. This setting is
|
||||
<strong>blocked for devices using cloud pollers</strong>
|
||||
and should only be used with local agents on trusted networks.
|
||||
</p>
|
||||
</div>
|
||||
<div class={"#{unless @form[:mikrotik_enabled].value, do: "hidden"} #{if @form[:mikrotik_use_ssl].value != false, do: "hidden"}"}>
|
||||
<div class="rounded-md bg-red-50 dark:bg-red-900/20 p-4">
|
||||
<p class="text-sm text-red-700 dark:text-red-300">
|
||||
<strong>Critical Security Warning:</strong>
|
||||
Plain API (port 8728) sends credentials unencrypted over the network. This setting is
|
||||
<strong>blocked for devices using cloud pollers</strong>
|
||||
and should only be used with local agents on trusted networks.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class={"col-span-full #{unless @form[:mikrotik_enabled].value, do: "hidden"} #{if @form[:mikrotik_use_ssl].value == false, do: "hidden"}"}>
|
||||
<div class="rounded-md bg-yellow-50 dark:bg-yellow-900/20 p-4">
|
||||
<p class="text-sm text-yellow-700 dark:text-yellow-300">
|
||||
<strong>Security Warning:</strong>
|
||||
Plain API (port 8728) sends credentials unencrypted. Use SSL (port 8729) whenever possible.
|
||||
</p>
|
||||
</div>
|
||||
<div class={"#{unless @form[:mikrotik_enabled].value, do: "hidden"} #{if @form[:mikrotik_use_ssl].value == false, do: "hidden"}"}>
|
||||
<div class="rounded-md bg-yellow-50 dark:bg-yellow-900/20 p-4">
|
||||
<p class="text-sm text-yellow-700 dark:text-yellow-300">
|
||||
<strong>Security Warning:</strong>
|
||||
Plain API (port 8728) sends credentials unencrypted. Use SSL (port 8729) whenever possible.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -317,78 +203,43 @@
|
|||
</div>
|
||||
|
||||
<div class="md:col-span-2">
|
||||
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:max-w-xl sm:grid-cols-6">
|
||||
<div class="col-span-full">
|
||||
<label
|
||||
for="default_agent_token_id"
|
||||
class="block text-sm/6 font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
Default Remote Agent
|
||||
</label>
|
||||
<div class="mt-2 grid grid-cols-1">
|
||||
<select
|
||||
name={@form[:default_agent_token_id].name}
|
||||
id="default_agent_token_id"
|
||||
class="col-start-1 row-start-1 w-full appearance-none rounded-md bg-white py-1.5 pr-8 pl-3 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:outline-white/10 dark:*:bg-gray-800 dark:focus:outline-indigo-500"
|
||||
>
|
||||
<option value="">No default agent - cloud polling</option>
|
||||
<%= for agent <- @available_agents do %>
|
||||
<option
|
||||
value={agent.id}
|
||||
selected={@form[:default_agent_token_id].value == agent.id}
|
||||
>
|
||||
{agent.name}
|
||||
</option>
|
||||
<% end %>
|
||||
</select>
|
||||
<svg
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
data-slot="icon"
|
||||
aria-hidden="true"
|
||||
class="pointer-events-none col-start-1 row-start-1 mr-2 size-5 self-center justify-self-end text-gray-400 sm:size-4"
|
||||
>
|
||||
<path
|
||||
d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z"
|
||||
clip-rule="evenodd"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<.input
|
||||
field={@form[:default_agent_token_id]}
|
||||
type="select"
|
||||
label="Default Remote Agent"
|
||||
prompt="No default agent - cloud polling"
|
||||
options={Enum.map(@available_agents, &{&1.name, &1.id})}
|
||||
/>
|
||||
|
||||
<div class="col-span-full">
|
||||
<div class="rounded-md bg-gray-50 dark:bg-gray-800/50 p-4">
|
||||
<p class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Current Device Assignment:
|
||||
</p>
|
||||
<div class="space-y-1 text-sm text-gray-600 dark:text-gray-400">
|
||||
<div class="flex items-center gap-2">
|
||||
<.icon name="hero-server" class="h-4 w-4" />
|
||||
<span>
|
||||
<strong>{@assignment_breakdown.direct}</strong> device-level override
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<.icon name="hero-building-office" class="h-4 w-4" />
|
||||
<span>
|
||||
<strong>{@assignment_breakdown.site}</strong> inherited from site
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<.icon name="hero-building-office-2" class="h-4 w-4" />
|
||||
<span>
|
||||
<strong>{@assignment_breakdown.organization}</strong>
|
||||
inheriting organization default
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<.icon name="hero-cloud" class="h-4 w-4" />
|
||||
<span>
|
||||
<strong>{@assignment_breakdown.cloud}</strong> cloud polling (no agent)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-md bg-gray-50 dark:bg-gray-800/50 p-4">
|
||||
<p class="text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
Current Device Assignment:
|
||||
</p>
|
||||
<div class="space-y-1 text-sm text-gray-600 dark:text-gray-400">
|
||||
<div class="flex items-center gap-2">
|
||||
<.icon name="hero-server" class="h-4 w-4" />
|
||||
<span>
|
||||
<strong>{@assignment_breakdown.direct}</strong> device-level override
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<.icon name="hero-building-office" class="h-4 w-4" />
|
||||
<span>
|
||||
<strong>{@assignment_breakdown.site}</strong> inherited from site
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<.icon name="hero-building-office-2" class="h-4 w-4" />
|
||||
<span>
|
||||
<strong>{@assignment_breakdown.organization}</strong>
|
||||
inheriting organization default
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<.icon name="hero-cloud" class="h-4 w-4" />
|
||||
<span>
|
||||
<strong>{@assignment_breakdown.cloud}</strong> cloud polling (no agent)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue