This commit is contained in:
Graham McIntire 2025-12-21 11:31:08 -06:00
parent ba463dc5a2
commit 20d2d8dbd8
No known key found for this signature in database
14 changed files with 120 additions and 123 deletions

View file

@ -1,6 +1,6 @@
[
import_deps: [:ecto, :ecto_sql, :phoenix],
subdirectories: ["priv/*/migrations"],
plugins: [Phoenix.LiveView.HTMLFormatter],
plugins: [Styler, Phoenix.LiveView.HTMLFormatter],
inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"]
]

View file

@ -7,30 +7,6 @@
# General application configuration
import Config
config :towerops,
ecto_repos: [Towerops.Repo],
generators: [timestamp_type: :utc_datetime, binary_id: true]
# Configure the endpoint
config :towerops, ToweropsWeb.Endpoint,
url: [host: "localhost"],
adapter: Bandit.PhoenixAdapter,
render_errors: [
formats: [html: ToweropsWeb.ErrorHTML, json: ToweropsWeb.ErrorJSON],
layout: false
],
pubsub_server: Towerops.PubSub,
live_view: [signing_salt: "Uh1ABfdI"]
# Configure the mailer
#
# By default it uses the "Local" adapter which stores the emails
# locally. You can see the emails in your browser, at "/dev/mailbox".
#
# For production it's recommended to configure a different adapter
# at the `config/runtime.exs`.
config :towerops, Towerops.Mailer, adapter: Swoosh.Adapters.Local
# Configure esbuild (the version is required)
config :esbuild,
version: "0.25.4",
@ -41,6 +17,14 @@ config :esbuild,
env: %{"NODE_PATH" => [Path.expand("../deps", __DIR__), Mix.Project.build_path()]}
]
# Configure Elixir's Logger
config :logger, :default_formatter,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
# Configure tailwind (the version is required)
config :tailwind,
version: "4.1.12",
@ -52,14 +36,30 @@ config :tailwind,
cd: Path.expand("..", __DIR__)
]
# Configure Elixir's Logger
config :logger, :default_formatter,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
# Configure the mailer
#
# By default it uses the "Local" adapter which stores the emails
# locally. You can see the emails in your browser, at "/dev/mailbox".
#
# For production it's recommended to configure a different adapter
# at the `config/runtime.exs`.
config :towerops, Towerops.Mailer, adapter: Swoosh.Adapters.Local
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
# Configure the endpoint
config :towerops, ToweropsWeb.Endpoint,
url: [host: "localhost"],
adapter: Bandit.PhoenixAdapter,
render_errors: [
formats: [html: ToweropsWeb.ErrorHTML, json: ToweropsWeb.ErrorJSON],
layout: false
],
pubsub_server: Towerops.PubSub,
live_view: [signing_salt: "Uh1ABfdI"]
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
config :towerops,
ecto_repos: [Towerops.Repo],
generators: [timestamp_type: :utc_datetime, binary_id: true]
import_config "#{config_env()}.exs"

View file

@ -1,5 +1,26 @@
import Config
# Do not include metadata nor timestamps in development logs
config :logger, :default_formatter, format: "[$level] $message\n"
# Initialize plugs at runtime for faster development compilation
config :phoenix, :plug_init_mode, :runtime
# Set a higher stacktrace during development. Avoid configuring such
# in production as building large stacktraces may be expensive.
config :phoenix, :stacktrace_depth, 20
config :phoenix_live_view,
# Include debug annotations and locations in rendered markup.
# Changing this configuration will require mix clean and a full recompile.
debug_heex_annotations: true,
debug_attributes: true,
# Enable helpful, but potentially expensive runtime checks
enable_expensive_runtime_checks: true
# Disable swoosh api client as it is only required for production adapters.
config :swoosh, :api_client, false
# Configure your database
config :towerops, Towerops.Repo,
username: "postgres",
@ -69,24 +90,3 @@ config :towerops, ToweropsWeb.Endpoint,
# Enable dev routes for dashboard and mailbox
config :towerops, dev_routes: true
# Do not include metadata nor timestamps in development logs
config :logger, :default_formatter, format: "[$level] $message\n"
# Set a higher stacktrace during development. Avoid configuring such
# in production as building large stacktraces may be expensive.
config :phoenix, :stacktrace_depth, 20
# Initialize plugs at runtime for faster development compilation
config :phoenix, :plug_init_mode, :runtime
config :phoenix_live_view,
# Include debug annotations and locations in rendered markup.
# Changing this configuration will require mix clean and a full recompile.
debug_heex_annotations: true,
debug_attributes: true,
# Enable helpful, but potentially expensive runtime checks
enable_expensive_runtime_checks: true
# Disable swoosh api client as it is only required for production adapters.
config :swoosh, :api_client, false

View file

@ -1,5 +1,14 @@
import Config
# Do not print debug messages in production
config :logger, level: :info
# Configure Swoosh API Client
config :swoosh, api_client: Swoosh.ApiClient.Req
# Disable Swoosh Local Memory Storage
config :swoosh, local: false
# Note we also include the path to a cache manifest
# containing the digested version of static files. This
# manifest is generated by the `mix assets.deploy` task,
@ -14,17 +23,7 @@ config :towerops, ToweropsWeb.Endpoint,
force_ssl: [rewrite_on: [:x_forwarded_proto]],
exclude: [
# paths: ["/health"],
hosts: ["localhost", "127.0.0.1"]
]
# Configure Swoosh API Client
config :swoosh, api_client: Swoosh.ApiClient.Req
# Disable Swoosh Local Memory Storage
config :swoosh, local: false
# Do not print debug messages in production
config :logger, level: :info
# Runtime production configuration, including reading
# of environment variables, is done on config/runtime.exs.
hosts: ["localhost", "127.0.0.1"]
]

View file

@ -20,8 +20,7 @@ if System.get_env("PHX_SERVER") do
config :towerops, ToweropsWeb.Endpoint, server: true
end
config :towerops, ToweropsWeb.Endpoint,
http: [port: String.to_integer(System.get_env("PORT", "4000"))]
config :towerops, ToweropsWeb.Endpoint, http: [port: String.to_integer(System.get_env("PORT", "4000"))]
if config_env() == :prod do
database_url =
@ -33,14 +32,6 @@ if config_env() == :prod do
maybe_ipv6 = if System.get_env("ECTO_IPV6") in ~w(true 1), do: [:inet6], else: []
config :towerops, Towerops.Repo,
# ssl: true,
url: database_url,
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
# For machines with several cores, consider starting multiple pools of `pool_size`
# pool_count: 4,
socket_options: maybe_ipv6
# The secret key base is used to sign/encrypt cookies and other secrets.
# A default value is used in config/dev.exs and config/test.exs but you
# want to use a different value for prod and you most likely don't want
@ -55,7 +46,13 @@ if config_env() == :prod do
host = System.get_env("PHX_HOST") || "example.com"
config :towerops, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY")
config :towerops, Towerops.Repo,
# ssl: true,
url: database_url,
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
# For machines with several cores, consider starting multiple pools of `pool_size`
# pool_count: 4,
socket_options: maybe_ipv6
config :towerops, ToweropsWeb.Endpoint,
url: [host: host, port: 443, scheme: "https"],
@ -68,6 +65,8 @@ if config_env() == :prod do
],
secret_key_base: secret_key_base
config :towerops, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY")
# ## SSL Support
#
# To get SSL working, you will need to add the `https` key

View file

@ -1,5 +1,25 @@
import Config
# Print only warnings and errors during test
config :logger, level: :warning
# Initialize plugs at runtime for faster test compilation
config :phoenix, :plug_init_mode, :runtime
# Sort query params output of verified routes for robust url comparisons
config :phoenix,
sort_verified_routes_query_params: true
# Enable helpful, but potentially expensive runtime checks
config :phoenix_live_view,
enable_expensive_runtime_checks: true
# Disable swoosh api client as it is only required for production adapters
config :swoosh, :api_client, false
# In test we don't send emails
config :towerops, Towerops.Mailer, adapter: Swoosh.Adapters.Test
# Configure your database
#
# The MIX_TEST_PARTITION environment variable can be used
@ -19,23 +39,3 @@ config :towerops, ToweropsWeb.Endpoint,
http: [ip: {127, 0, 0, 1}, port: 4002],
secret_key_base: "XDSSqVUtRXUjEfzxefIAaPIzBfonpNMOrCRyP1a0kjPzzyOpVNSRmMBVae/bwTqj",
server: false
# In test we don't send emails
config :towerops, Towerops.Mailer, adapter: Swoosh.Adapters.Test
# Disable swoosh api client as it is only required for production adapters
config :swoosh, :api_client, false
# Print only warnings and errors during test
config :logger, level: :warning
# Initialize plugs at runtime for faster test compilation
config :phoenix, :plug_init_mode, :runtime
# Enable helpful, but potentially expensive runtime checks
config :phoenix_live_view,
enable_expensive_runtime_checks: true
# Sort query params output of verified routes for robust url comparisons
config :phoenix,
sort_verified_routes_query_params: true

View file

@ -1,3 +1,4 @@
defmodule Towerops.Mailer do
@moduledoc false
use Swoosh.Mailer, otp_app: :towerops
end

View file

@ -23,10 +23,11 @@ defmodule ToweropsWeb do
quote do
use Phoenix.Router, helpers: false
# Import common connection and controller functions to use in pipelines
import Plug.Conn
import Phoenix.Controller
import Phoenix.LiveView.Router
# Import common connection and controller functions to use in pipelines
import Plug.Conn
end
end
@ -39,7 +40,6 @@ defmodule ToweropsWeb do
def controller do
quote do
use Phoenix.Controller, formats: [:html, :json]
use Gettext, backend: ToweropsWeb.Gettext
import Plug.Conn

View file

@ -29,6 +29,7 @@ defmodule ToweropsWeb.CoreComponents do
use Phoenix.Component
use Gettext, backend: ToweropsWeb.Gettext
alias Phoenix.HTML.FormField
alias Phoenix.LiveView.JS
@doc """
@ -166,8 +167,7 @@ defmodule ToweropsWeb.CoreComponents do
values: ~w(checkbox color date datetime-local email file month number password
search select tel text textarea time url week hidden)
attr :field, Phoenix.HTML.FormField,
doc: "a form field struct retrieved from the form, for example: @form[:email]"
attr :field, FormField, doc: "a form field struct retrieved from the form, for example: @form[:email]"
attr :errors, :list, default: []
attr :checked, :boolean, doc: "the checked flag for checkbox inputs"
@ -177,11 +177,10 @@ defmodule ToweropsWeb.CoreComponents do
attr :class, :any, default: nil, doc: "the input class to use over defaults"
attr :error_class, :any, default: nil, doc: "the input error class to use over defaults"
attr :rest, :global,
include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength
attr :rest, :global, include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength
multiple pattern placeholder readonly required rows size step)
def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
def input(%{field: %FormField{} = field} = assigns) do
errors = if Phoenix.Component.used_input?(field), do: field.errors, else: []
assigns
@ -452,8 +451,7 @@ defmodule ToweropsWeb.CoreComponents do
to: selector,
time: 300,
transition:
{"transition-all ease-out duration-300",
"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95",
{"transition-all ease-out duration-300", "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95",
"opacity-100 translate-y-0 sm:scale-100"}
)
end

View file

@ -1,5 +1,7 @@
defmodule ToweropsWeb.Telemetry do
@moduledoc false
use Supervisor
import Telemetry.Metrics
def start_link(arg) do
@ -71,8 +73,7 @@ defmodule ToweropsWeb.Telemetry do
),
summary("towerops.repo.query.idle_time",
unit: {:native, :millisecond},
description:
"The time the connection spent waiting before being checked out for the query"
description: "The time the connection spent waiting before being checked out for the query"
),
# VM Metrics

10
mix.exs
View file

@ -52,12 +52,7 @@ defmodule Towerops.MixProject do
{:esbuild, "~> 0.10", runtime: Mix.env() == :dev},
{:tailwind, "~> 0.3", runtime: Mix.env() == :dev},
{:heroicons,
github: "tailwindlabs/heroicons",
tag: "v2.2.0",
sparse: "optimized",
app: false,
compile: false,
depth: 1},
github: "tailwindlabs/heroicons", tag: "v2.2.0", sparse: "optimized", app: false, compile: false, depth: 1},
{:swoosh, "~> 1.16"},
{:req, "~> 0.5"},
{:telemetry_metrics, "~> 1.0"},
@ -65,7 +60,8 @@ defmodule Towerops.MixProject do
{:gettext, "~> 1.0"},
{:jason, "~> 1.2"},
{:dns_cluster, "~> 0.2.0"},
{:bandit, "~> 1.5"}
{:bandit, "~> 1.5"},
{:styler, "~> 1.10", only: [:dev, :test], runtime: false}
]
end

View file

@ -34,6 +34,7 @@
"plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"},
"postgrex": {:hex, :postgrex, "0.21.1", "2c5cc830ec11e7a0067dd4d623c049b3ef807e9507a424985b8dcf921224cd88", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "27d8d21c103c3cc68851b533ff99eef353e6a0ff98dc444ea751de43eb48bdac"},
"req": {:hex, :req, "0.5.16", "99ba6a36b014458e52a8b9a0543bfa752cb0344b2a9d756651db1281d4ba4450", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "974a7a27982b9b791df84e8f6687d21483795882a7840e8309abdbe08bb06f09"},
"styler": {:hex, :styler, "1.10.0", "343f1f7bb19a8893c2841a9ae90665b68d2edf6cc37b964a5099e60c78815c2e", [:mix], [], "hexpm", "6a78876611869466139e63722df4cbbb56b18a842d88c19f23ca844d914ad91a"},
"swoosh": {:hex, :swoosh, "1.19.9", "4eb2c471b8cf06adbdcaa1d57a0ad53c0ed9348ce8586a06cc491f9f0dbcb553", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5.10 or ~> 0.6 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "516898263a64925c31723c56bc7999a26e97b04e869707f681f4c9bca7ee1688"},
"tailwind": {:hex, :tailwind, "0.4.1", "e7bcc222fe96a1e55f948e76d13dd84a1a7653fb051d2a167135db3b4b08d3e9", [:mix], [], "hexpm", "6249d4f9819052911120dbdbe9e532e6bd64ea23476056adb7f730aa25c220d1"},
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},

View file

@ -19,15 +19,15 @@ defmodule ToweropsWeb.ConnCase do
using do
quote do
use ToweropsWeb, :verified_routes
import Phoenix.ConnTest
import Plug.Conn
import ToweropsWeb.ConnCase
# The default endpoint for testing
@endpoint ToweropsWeb.Endpoint
use ToweropsWeb, :verified_routes
# Import conveniences for testing with connections
import Plug.Conn
import Phoenix.ConnTest
import ToweropsWeb.ConnCase
end
end

View file

@ -16,14 +16,16 @@ defmodule Towerops.DataCase do
use ExUnit.CaseTemplate
alias Ecto.Adapters.SQL.Sandbox
using do
quote do
alias Towerops.Repo
import Ecto
import Ecto.Changeset
import Ecto.Query
import Towerops.DataCase
alias Towerops.Repo
end
end
@ -36,8 +38,8 @@ defmodule Towerops.DataCase do
Sets up the sandbox based on the test tags.
"""
def setup_sandbox(tags) do
pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Towerops.Repo, shared: not tags[:async])
on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
pid = Sandbox.start_owner!(Towerops.Repo, shared: not tags[:async])
on_exit(fn -> Sandbox.stop_owner(pid) end)
end
@doc """