A Phoenix LiveView dashboard for monitoring PgFlow workflows, jobs, and cron schedules.
mix pgflow_dashboard.gen.migration
mix ecto.migrateThis installs the pgflow_dashboard PostgreSQL schema with read-only views and query functions.
In lib/my_app/application.ex:
children = [
MyApp.Repo,
MyAppWeb.Endpoint,
PgFlowDashboard
]In lib/my_app_web/router.ex:
import PgFlowDashboard.Router
scope "/" do
pipe_through [:browser]
pgflow_dashboard "/pgflow",
repo: MyApp.Repo,
pubsub: MyApp.PubSub
endThe dashboard's Runs page uses LiveFilter for filtering and pagination. Since it's an optional dependency of pgflow, you must add it explicitly:
# mix.exs
def deps do
[
{:pgflow, "~> 0.1.0"},
{:live_filter, github: "agoodway/livefilter"}
]
endThen fetch:
mix deps.getJavaScript hooks — Add both PgFlow Dashboard and LiveFilter hooks to your LiveSocket in assets/js/app.js:
import { DarkMode, KeyboardShortcuts, ShortcutsModal, MobileMenu } from "../../deps/pgflow/priv/static/pgflow_dashboard/hooks"
import { hooks as liveFilterHooks } from "live_filter"
let liveSocket = new LiveSocket("/live", Socket, {
hooks: { ...liveFilterHooks, DarkMode, KeyboardShortcuts, ShortcutsModal, MobileMenu, ...yourOtherHooks }
})esbuild — LiveFilter's JS import requires NODE_PATH to resolve deps/. In config/config.exs:
config :esbuild,
version: "0.25.4",
my_app: [
args: ~w(js/app.js --bundle --target=es2022 --outdir=../priv/static/assets/js),
cd: Path.expand("../assets", __DIR__),
env: %{
"NODE_PATH" => Path.expand("../deps", __DIR__)
}
]Tailwind — Add LiveFilter and DaisyUI component paths so Tailwind generates their classes. In your CSS file (e.g. assets/css/app.css):
@source "../../deps/daisy_ui_components";
@source "../../deps/live_filter";Or if using tailwind.config.js:
module.exports = {
content: [
// ... existing paths ...
"../deps/daisy_ui_components/**/*.*ex",
"../deps/live_filter/**/*.*ex",
],
}Start your server and navigate to /pgflow.
Protect the dashboard in production. Use pipe_through to guard the routes:
scope "/" do
pipe_through [:browser, :require_authenticated_admin]
pgflow_dashboard "/pgflow",
repo: MyApp.Repo,
pubsub: MyApp.PubSub
endOr use the :on_mount option for LiveView-level auth:
pgflow_dashboard "/pgflow",
repo: MyApp.Repo,
pubsub: MyApp.PubSub,
on_mount: [{MyAppWeb.AdminAuth, :ensure_admin}]| Option | Type | Default | Description |
|---|---|---|---|
repo |
atom | required | Ecto repository module |
pubsub |
atom | required | Phoenix.PubSub module |
refresh_interval |
integer | 5_000 |
Auto-refresh interval in ms |
time_zone |
string | "UTC" |
Time zone for timestamps |
default_time_range |
atom | :last_24h |
Default filter (:last_hour, :last_24h, :last_7d, :last_30d) |
max_grid_runs |
integer | 50 |
Max runs shown in the activity grid |
query_timeout |
integer | 10_000 |
Database query timeout in ms |
enable_pubsub |
boolean | true |
Enable real-time PubSub updates |
cache_ttl |
integer | 5_000 |
Cache TTL for aggregation queries in ms |
Active workers, running count, 24h completions/failures, average duration. Lists recent runs and worker status.
All registered flow definitions with 24h statistics (runs, success rate, avg duration).
Flow configuration, run history, and GitHub-style activity grid.
Background job definitions with 24h statistics. Card view for 12 or fewer jobs, paginated table for more.
Job configuration and run history.
Scheduled recurring jobs showing cron expression, human-readable schedule, next run time, and active/inactive status.
Schedule details and run history for a cron.
Filterable list of all workflow and job runs with status, progress, and duration.
Interactive SVG dependency graph, step execution timeline, and input/output data inspection.
Worker processes with health status (healthy, stale, dead) and active task counts.
Worker metadata and task throughput.
Press ? to see all shortcuts.
| Shortcut | Action |
|---|---|
g o |
Go to Overview |
g w |
Go to Workers |
g r |
Go to Runs |
g f |
Go to Flows |
g j |
Go to Jobs |
g c |
Go to Crons |
d |
Toggle dark mode |
? |
Show shortcuts |
Esc |
Close modal |
For high-traffic dashboards:
mix pgflow_dashboard.gen.indexes
mix ecto.migrateNo data showing -- Verify the migration ran: SELECT * FROM pgflow_dashboard.get_overview_metrics();
Real-time updates not working -- Check that PubSub is configured and the PgFlowDashboard supervisor is running.
Hooks not working -- Verify all four hooks (DarkMode, KeyboardShortcuts, ShortcutsModal, MobileMenu) and liveFilterHooks are registered with your LiveSocket.
Runs page filters not rendering -- Ensure live_filter is in your deps, esbuild NODE_PATH includes deps/, and Tailwind scans daisy_ui_components and live_filter paths.