diff --git a/assets/css/admin/icons.css b/assets/css/admin/icons.css index fba621f..b6c7058 100644 --- a/assets/css/admin/icons.css +++ b/assets/css/admin/icons.css @@ -2,6 +2,30 @@ @layer admin { +.hero-arrow-down-tray { + --hero-arrow-down-tray: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-arrow-down-tray); + mask: var(--hero-arrow-down-tray); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + +.hero-arrow-left { + --hero-arrow-left: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-arrow-left); + mask: var(--hero-arrow-left); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-arrow-left-mini { --hero-arrow-left-mini: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-arrow-left-mini); @@ -74,6 +98,18 @@ height: 1.25rem; } +.hero-arrow-up-tray { + --hero-arrow-up-tray: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-arrow-up-tray); + mask: var(--hero-arrow-up-tray); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-arrow-uturn-left { --hero-arrow-uturn-left: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-arrow-uturn-left); @@ -110,6 +146,18 @@ height: 1.5rem; } +.hero-arrows-up-down { + --hero-arrows-up-down: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-arrows-up-down); + mask: var(--hero-arrows-up-down); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-banknotes { --hero-banknotes: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-banknotes); @@ -134,6 +182,18 @@ height: 1.5rem; } +.hero-bell { + --hero-bell: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-bell); + mask: var(--hero-bell); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-bug-ant { --hero-bug-ant: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-bug-ant); @@ -230,6 +290,18 @@ height: 1.25rem; } +.hero-chevron-down { + --hero-chevron-down: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-chevron-down); + mask: var(--hero-chevron-down); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-chevron-down-mini { --hero-chevron-down-mini: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-chevron-down-mini); @@ -242,6 +314,18 @@ height: 1.25rem; } +.hero-chevron-left { + --hero-chevron-left: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-chevron-left); + mask: var(--hero-chevron-left); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-chevron-right { --hero-chevron-right: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-chevron-right); @@ -266,6 +350,18 @@ height: 1.25rem; } +.hero-chevron-up { + --hero-chevron-up: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-chevron-up); + mask: var(--hero-chevron-up); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-chevron-up-mini { --hero-chevron-up-mini: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-chevron-up-mini); @@ -326,6 +422,18 @@ height: 1.25rem; } +.hero-code-bracket { + --hero-code-bracket: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-code-bracket); + mask: var(--hero-code-bracket); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-cog-6-tooth { --hero-cog-6-tooth: url('data:image/svg+xml;utf8,%20%20%20%20'); -webkit-mask: var(--hero-cog-6-tooth); @@ -374,6 +482,18 @@ height: 1.5rem; } +.hero-cursor-arrow-rays { + --hero-cursor-arrow-rays: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-cursor-arrow-rays); + mask: var(--hero-cursor-arrow-rays); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-document { --hero-document: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-document); @@ -386,6 +506,18 @@ height: 1.5rem; } +.hero-document-duplicate { + --hero-document-duplicate: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-document-duplicate); + mask: var(--hero-document-duplicate); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-document-duplicate-mini { --hero-document-duplicate-mini: url('data:image/svg+xml;utf8,%20%20%20%20'); -webkit-mask: var(--hero-document-duplicate-mini); @@ -398,6 +530,18 @@ height: 1.25rem; } +.hero-document-plus { + --hero-document-plus: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-document-plus); + mask: var(--hero-document-plus); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-document-text { --hero-document-text: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-document-text); @@ -554,6 +698,18 @@ height: 1.5rem; } +.hero-information-circle-mini { + --hero-information-circle-mini: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-information-circle-mini); + mask: var(--hero-information-circle-mini); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.25rem; + height: 1.25rem; +} + .hero-link { --hero-link: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-link); @@ -590,6 +746,18 @@ height: 1.5rem; } +.hero-magnifying-glass-mini { + --hero-magnifying-glass-mini: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-magnifying-glass-mini); + mask: var(--hero-magnifying-glass-mini); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.25rem; + height: 1.25rem; +} + .hero-megaphone { --hero-megaphone: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-megaphone); @@ -602,6 +770,18 @@ height: 1.5rem; } +.hero-minus { + --hero-minus: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-minus); + mask: var(--hero-minus); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-minus-circle-mini { --hero-minus-circle-mini: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-minus-circle-mini); @@ -686,6 +866,18 @@ height: 1.25rem; } +.hero-pencil-square { + --hero-pencil-square: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-pencil-square); + mask: var(--hero-pencil-square); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-photo { --hero-photo: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-photo); @@ -698,6 +890,18 @@ height: 1.5rem; } +.hero-play { + --hero-play: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-play); + mask: var(--hero-play); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-plus { --hero-plus: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-plus); @@ -746,6 +950,18 @@ height: 1.25rem; } +.hero-queue-list { + --hero-queue-list: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-queue-list); + mask: var(--hero-queue-list); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-rocket-launch-mini { --hero-rocket-launch-mini: url('data:image/svg+xml;utf8,%20%20%20%20'); -webkit-mask: var(--hero-rocket-launch-mini); @@ -878,6 +1094,18 @@ height: 1.5rem; } +.hero-trash { + --hero-trash: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-trash); + mask: var(--hero-trash); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.5rem; + height: 1.5rem; +} + .hero-trash-mini { --hero-trash-mini: url('data:image/svg+xml;utf8,%20%20'); -webkit-mask: var(--hero-trash-mini); @@ -974,4 +1202,16 @@ height: 1.5rem; } +.hero-x-mark-mini { + --hero-x-mark-mini: url('data:image/svg+xml;utf8,%20%20'); + -webkit-mask: var(--hero-x-mark-mini); + mask: var(--hero-x-mark-mini); + mask-repeat: no-repeat; + background-color: currentColor; + vertical-align: middle; + display: inline-block; + width: 1.25rem; + height: 1.25rem; +} + } /* @layer admin */ diff --git a/lib/berrypod_web/components/layouts/admin.html.heex b/lib/berrypod_web/components/layouts/admin.html.heex index da78aed..d2ad7a5 100644 --- a/lib/berrypod_web/components/layouts/admin.html.heex +++ b/lib/berrypod_web/components/layouts/admin.html.heex @@ -208,6 +208,11 @@ <.icon name="hero-bug-ant" class="size-5" /> Errors +
  • + <.link href={~p"/admin/oban"}> + <.icon name="hero-queue-list" class="size-5" /> Jobs + +
  • <.link href={~p"/users/log-out"} method="delete"> <.icon name="hero-arrow-right-start-on-rectangle" class="size-5" /> Log out diff --git a/lib/berrypod_web/oban_resolver.ex b/lib/berrypod_web/oban_resolver.ex new file mode 100644 index 0000000..7b5aa57 --- /dev/null +++ b/lib/berrypod_web/oban_resolver.ex @@ -0,0 +1,9 @@ +defmodule BerrypodWeb.ObanResolver do + @behaviour Oban.Web.Resolver + + @impl true + def resolve_user(conn), do: conn.assigns[:current_scope] + + @impl true + def resolve_access(_user), do: :all +end diff --git a/lib/berrypod_web/router.ex b/lib/berrypod_web/router.ex index 08785b2..5af14d8 100644 --- a/lib/berrypod_web/router.ex +++ b/lib/berrypod_web/router.ex @@ -4,6 +4,7 @@ defmodule BerrypodWeb.Router do import BerrypodWeb.UserAuth import Phoenix.LiveDashboard.Router import ErrorTracker.Web.Router + import Oban.Web.Router pipeline :browser do plug :accepts, ["html"] @@ -123,12 +124,13 @@ defmodule BerrypodWeb.Router do end end - # LiveDashboard and ErrorTracker behind admin auth (available in all environments) + # LiveDashboard, ErrorTracker, and Oban Web behind admin auth scope "/admin" do pipe_through [:browser, :require_authenticated_user] live_dashboard "/dashboard", metrics: BerrypodWeb.Telemetry error_tracker_dashboard("/errors") + oban_dashboard("/oban", resolver: BerrypodWeb.ObanResolver) end # Admin pages with sidebar layout diff --git a/mix.exs b/mix.exs index 5cc7945..0cfd039 100644 --- a/mix.exs +++ b/mix.exs @@ -72,7 +72,8 @@ defmodule Berrypod.MixProject do {:bandit, "~> 1.5"}, {:tidewave, "~> 0.5", only: :dev}, {:image, "~> 0.54"}, - {:oban, "~> 2.18"}, + {:oban, "~> 2.19"}, + {:oban_web, "~> 2.11"}, {:ex_money, "~> 5.0"}, {:ex_money_sql, "~> 1.0"}, {:stripity_stripe, "~> 3.2"}, diff --git a/mix.lock b/mix.lock index 00c217e..6792d48 100644 --- a/mix.lock +++ b/mix.lock @@ -50,6 +50,8 @@ "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "oban": {:hex, :oban, "2.20.2", "f23313d83b578305cafa825a036cad84e7e2d61549ecbece3a2e6526d347cc3b", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:igniter, "~> 0.5", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.20", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 1.3", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "523365ef0217781c061d15f496e3200a5f1b43e08b1a27c34799ef8bfe95815f"}, + "oban_met": {:hex, :oban_met, "1.0.6", "2a5500aff496b7ac4b830b0b03b08e920625a051bb6890981fbb53b15f1cbdc0", [:mix], [{:oban, "~> 2.19", [hex: :oban, repo: "hexpm", optional: false]}], "hexpm", "15ea3303de76225878a8e6c25a9d62bd1e2e9dd1c46ac8487d873b9f99e8dcee"}, + "oban_web": {:hex, :oban_web, "2.11.8", "be6521b5b1eb6d4182f40f5acc948ea65d243451b94c26f06a7329575748f695", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}, {:oban, "~> 2.19", [hex: :oban, repo: "hexpm", optional: false]}, {:oban_met, "~> 1.0", [hex: :oban_met, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.7", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}], "hexpm", "d0c04a836d929ef037e96be142285238275aabbafe62543bbdcc3f541d29ec30"}, "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "phoenix": {:hex, :phoenix, "1.8.3", "49ac5e485083cb1495a905e47eb554277bdd9c65ccb4fc5100306b350151aa95", [:mix], [{:bandit, "~> 1.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "36169f95cc2e155b78be93d9590acc3f462f1e5438db06e6248613f27c80caec"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.7.0", "75c4b9dfb3efdc42aec2bd5f8bccd978aca0651dbcbc7a3f362ea5d9d43153c6", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "1d75011e4254cb4ddf823e81823a9629559a1be93b4321a6a5f11a5306fbf4cc"},