Current section
Files
Jump to
Current section
Files
lib/mix/tasks/dala.web.ex
defmodule Mix.Tasks.Dala.Web do
@moduledoc """
Start the Dala Web UI - a comprehensive web interface for all dala_dev features.
This task starts a Phoenix + Bandit web server that provides a unified
dashboard for all mobile development tools including device management,
deployment, emulators, provisioning, observer, and more.
mix dala.web
mix dala.web --port 4000 # default port
mix dala.web --no-browser # don't open browser automatically
## Features
The web UI provides access to:
- **Dashboard**: Device status, quick actions, system overview
- **Devices**: Android and iOS device management
- **Deploy**: Application deployment to devices
- **Emulators**: Manage Android AVDs and iOS simulators
- **Observer**: Remote node monitoring (web-based :observer)
- **Provision**: Code signing and provisioning profile management
- **Release**: Build and manage releases for Android and iOS
- **Profiling**: Performance profiling and analysis
- **CI Testing**: Continuous integration test management
- **Logs**: Centralized log viewing and filtering
- **Settings**: Configuration and preferences
## Options
- `--port` / `-p`: Port to run the server on (default: 4000)
- `--no-browser`: Don't open the browser automatically
- `--node` / `-n`: Connect to a remote node
- `--name`: Node name for distributed mode
- `--cookie`: Cookie for distributed mode
## Examples
mix dala.web
mix dala.web --port 8080
mix dala.web --no-browser
mix dala.web --node other@host --name mynode
"""
use Mix.Task
@default_port 4000
@impl Mix.Task
def run(args) do
{opts, _, _} =
OptionParser.parse(args,
switches: [
port: :integer,
browser: :boolean,
node: :string,
name: :string,
cookie: :string
],
aliases: [p: :port, n: :node]
)
port = Keyword.get(opts, :port, @default_port)
open_browser? = Keyword.get(opts, :browser, true)
target_node = Keyword.get(opts, :node, nil)
node_name = Keyword.get(opts, :name, nil)
cookie = Keyword.get(opts, :cookie, :erlang.get_cookie())
# Setup distributed node if requested
if node_name do
{:ok, _} = Node.start(:"#{node_name}", :shortnames)
end
if cookie do
Node.set_cookie(cookie |> to_string() |> String.to_atom())
end
if target_node do
target = target_node |> to_string() |> String.to_atom()
case Node.connect(target) do
true -> Mix.shell().info("Connected to #{target}")
false -> Mix.shell().error("Failed to connect to #{target}")
end
end
# Configure the endpoint
configure_endpoint(port)
lan_ip = DalaDev.Network.lan_ip()
# Start required applications
{:ok, _} = Application.ensure_all_started(:bandit)
{:ok, _} = Application.ensure_all_started(:phoenix_live_view)
{:ok, _} = Application.ensure_all_started(:phoenix_pubsub)
# Start supervisor with all components
children = [
{Phoenix.PubSub, name: DalaDev.PubSub},
DalaDev.Server.LogBuffer,
DalaDev.Server.ElixirLogBuffer,
DalaDev.Server.Endpoint,
DalaDev.Server.DevicePoller,
DalaDev.Server.LogStreamerSupervisor,
DalaDev.Server.WatchWorker,
{Task.Supervisor, name: DalaDev.Server.TaskSupervisor}
]
{:ok, sup} =
Supervisor.start_link(children, strategy: :one_for_one, name: DalaDev.Server.Supervisor)
# Attach the Elixir logger handler
DalaDev.Server.ElixirLogger.attach()
# Print startup information
local_url = "http://localhost:#{port}"
IO.puts("")
IO.puts("#{IO.ANSI.cyan()}=== Dala Web UI ===#{IO.ANSI.reset()}")
IO.puts(" #{IO.ANSI.green()}#{local_url}#{IO.ANSI.reset()}")
IO.puts(" #{IO.ANSI.cyan()}All dala_dev features available at:#{IO.ANSI.reset()}")
IO.puts(" #{local_url}/dashboard")
IO.puts(" #{local_url}/devices")
IO.puts(" #{local_url}/deploy")
IO.puts(" #{local_url}/emulators")
IO.puts(" #{local_url}/observer")
IO.puts(" #{local_url}/provision")
IO.puts(" #{local_url}/release")
IO.puts(" #{local_url}/profiling")
IO.puts(" #{local_url}/ci")
IO.puts(" #{local_url}/logs")
if lan_ip do
lan_url = "http://#{:inet.ntoa(lan_ip)}:#{port}"
IO.puts("")
IO.puts(" #{IO.ANSI.green()}LAN: #{lan_url}#{IO.ANSI.reset()} ← open on phone")
IO.puts("")
IO.puts(DalaDev.QR.render(lan_url))
end
IO.puts("")
# Open browser if requested
if open_browser? do
open_browser(local_url)
end
if IEx.started?() do
Process.unlink(sup)
IO.puts(" #{IO.ANSI.green()}IEx ready.#{IO.ANSI.reset()}")
IO.puts("")
else
IO.puts(" Press Ctrl+C to stop.")
IO.puts("")
Process.sleep(:infinity)
end
end
defp configure_endpoint(port) do
Application.put_env(:dala_dev, DalaDev.Server.Endpoint,
adapter: Bandit.PhoenixAdapter,
http: [ip: {0, 0, 0, 0}, port: port],
url: [host: "localhost", port: port],
server: true,
live_view: [signing_salt: "dala_dev_web_salt"],
secret_key_base: String.duplicate("dala_dev_web_secret_key_base_not_for_production_", 2)
)
end
defp open_browser(url) do
cmd =
case :os.type() do
{:unix, :darwin} -> "open"
{:unix, _} -> "xdg-open"
{:win32, _} -> "start"
end
Task.start(fn ->
:timer.sleep(500)
System.cmd(cmd, [url], stderr_to_stdout: true)
end)
end
end