CRITICAL: - Membership: remove :role/:org_id/:user_id from mass-assignment cast; use explicit create_changeset/4 and role_update_changeset/2 - GraphQL member resolver: add authorize_invite/3 checking admin/owner role and role hierarchy - REST invitations controller: add auth check for invite creation HIGH: - ApiToken: remove :organization_id/:user_id from cast; use explicit create_changeset/4 MEDIUM: - Move 8 LiveView Ecto queries into context modules (Admin, Alerts, Coverages, OnCall, Snmp) - Replace Process.put/Process.get with socket assigns for unresolved_alert_count (user_auth + layouts + 50 templates) - Add batch get_utilization_for_interfaces/1 to eliminate N+1 capacity queries in device show - Replace Process.sleep with Process.monitor/assert_receive or Process.send_after in 5 test files LOW: - Add handle_params/3 to UserResetPasswordLive, UserRegistrationLive, StatusPageLive - Remove redundant Repo.preload calls; add preloads to list_site_devices/1 - Fix @impl annotations and credo nesting warnings
45 lines
1.5 KiB
Elixir
45 lines
1.5 KiB
Elixir
defmodule ToweropsWeb.ChangelogLive do
|
|
@moduledoc false
|
|
use ToweropsWeb, :live_view
|
|
|
|
@impl true
|
|
def mount(_params, _session, socket) do
|
|
entries = ToweropsWeb.ChangelogParser.parse()
|
|
{:ok, assign(socket, entries: entries, page_title: "What's New")}
|
|
end
|
|
|
|
@impl true
|
|
def render(assigns) do
|
|
~H"""
|
|
<Layouts.authenticated
|
|
flash={@flash}
|
|
current_scope={@current_scope}
|
|
active_page="changelog"
|
|
unresolved_alert_count={assigns[:unresolved_alert_count] || 0}
|
|
>
|
|
<div class="mx-auto max-w-3xl px-4 py-8">
|
|
<h1 class="text-3xl font-bold mb-2">What's New</h1>
|
|
<p class="text-base-content/60 mb-8">Latest updates and improvements to TowerOps.</p>
|
|
|
|
<div class="space-y-8">
|
|
<div :for={entry <- @entries} class="relative pl-8 border-l-2 border-primary/20">
|
|
<div class="absolute -left-[9px] top-1 w-4 h-4 rounded-full bg-primary border-2 border-base-100" />
|
|
<div class="mb-1">
|
|
<span class="badge badge-ghost badge-sm font-mono">
|
|
{Calendar.strftime(entry.date, "%b %d, %Y")}
|
|
</span>
|
|
</div>
|
|
<h2 :if={entry.title} class="text-lg font-semibold mb-2">{entry.title}</h2>
|
|
<ul
|
|
:if={entry.items != []}
|
|
class="list-disc list-inside space-y-1 text-base-content/80 text-sm"
|
|
>
|
|
<li :for={item <- entry.items}>{item}</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Layouts.authenticated>
|
|
"""
|
|
end
|
|
end
|