Skip to content

Commit cf3fb7d

Browse files
authored
Merge pull request #28 from baselinrhq/feat/ui-cli
feat: Added ui cli command
2 parents 7a41f67 + 6bedd49 commit cf3fb7d

File tree

16 files changed

+1096
-28
lines changed

16 files changed

+1096
-28
lines changed

README.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
- **Dagster Integration**: Built-in orchestration support with Dagster assets and schedules
2828
- **Configuration-Driven**: Simple YAML/JSON configuration for defining profiling targets
2929
- **Historical Tracking**: Store profiling results over time for trend analysis
30-
- **CLI Interface**: Comprehensive command-line interface for profiling, drift detection, querying, and schema management
30+
- **CLI Interface**: Comprehensive command-line interface for profiling, drift detection, querying, schema management, and dashboard UI
3131

3232
## 📋 Requirements
3333

@@ -190,7 +190,24 @@ baselinr status --config config.yml --watch
190190
baselinr status --config config.yml --json
191191
```
192192

193-
### 7. Manage Schema Migrations
193+
### 7. Start Dashboard UI
194+
195+
Launch the web dashboard to view profiling runs, drift alerts, and metrics:
196+
197+
```bash
198+
# Start dashboard (foreground mode)
199+
baselinr ui --config config.yml
200+
201+
# Custom ports
202+
baselinr ui --config config.yml --port-backend 8080 --port-frontend 3001
203+
204+
# Localhost only
205+
baselinr ui --config config.yml --host 127.0.0.1
206+
```
207+
208+
Press `Ctrl+C` to stop the dashboard. See [docs/schemas/UI_COMMAND.md](docs/schemas/UI_COMMAND.md) for more details.
209+
210+
### 8. Manage Schema Migrations
194211

195212
Check and apply schema migrations:
196213

@@ -447,6 +464,9 @@ baselinr status --config examples/config.yml --watch
447464
# Status with JSON output
448465
baselinr status --config examples/config.yml --json
449466

467+
# Start dashboard UI
468+
baselinr ui --config examples/config.yml
469+
450470
# Check schema migration status
451471
baselinr migrate status --config examples/config.yml
452472

baselinr/cli.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,36 @@ def query_command(args):
584584
return 1
585585

586586

587+
def ui_command(args):
588+
"""Execute UI command."""
589+
try:
590+
# Load configuration
591+
config = ConfigLoader.load_from_file(args.config)
592+
593+
# Import UI startup function
594+
from .ui import start_dashboard_foreground
595+
from .ui.dependencies import check_all_dependencies
596+
597+
# Check dependencies first
598+
check_all_dependencies(config, args.port_backend, args.port_frontend, args.host)
599+
600+
# Start dashboard in foreground
601+
start_dashboard_foreground(
602+
config,
603+
backend_port=args.port_backend,
604+
frontend_port=args.port_frontend,
605+
backend_host=args.host,
606+
)
607+
return 0
608+
except KeyboardInterrupt:
609+
logger.info("UI command interrupted by user")
610+
return 0
611+
except Exception as e:
612+
logger.error(f"UI command failed: {e}", exc_info=True)
613+
print(f"\nError: {e}")
614+
return 1
615+
616+
587617
def status_command(args):
588618
"""Execute status command."""
589619
try:
@@ -1220,6 +1250,30 @@ def main():
12201250
help="Auto-refresh every N seconds (default: 5). Use --watch 0 to disable.",
12211251
)
12221252

1253+
# UI command
1254+
ui_parser = subparsers.add_parser("ui", help="Start local dashboard")
1255+
ui_parser.add_argument(
1256+
"--config", "-c", required=True, help="Path to configuration file (YAML or JSON)"
1257+
)
1258+
ui_parser.add_argument(
1259+
"--port-backend",
1260+
type=int,
1261+
default=8000,
1262+
help="Backend API port (default: 8000)",
1263+
)
1264+
ui_parser.add_argument(
1265+
"--port-frontend",
1266+
type=int,
1267+
default=3000,
1268+
help="Frontend UI port (default: 3000)",
1269+
)
1270+
ui_parser.add_argument(
1271+
"--host",
1272+
type=str,
1273+
default="0.0.0.0",
1274+
help="Backend host (default: 0.0.0.0)",
1275+
)
1276+
12231277
# Parse arguments
12241278
args = parser.parse_args()
12251279

@@ -1246,6 +1300,8 @@ def main():
12461300
return query_command(args)
12471301
elif args.command == "status":
12481302
return status_command(args)
1303+
elif args.command == "ui":
1304+
return ui_command(args)
12491305
else:
12501306
parser.print_help()
12511307
return 1

baselinr/ui/__init__.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""UI command utilities for Baselinr dashboard."""
2+
3+
from .config_builder import build_connection_string
4+
from .dependencies import (
5+
check_all_dependencies,
6+
check_database_connection,
7+
check_nodejs,
8+
check_ports,
9+
check_python_packages,
10+
)
11+
from .startup import start_dashboard_foreground
12+
13+
__all__ = [
14+
"build_connection_string",
15+
"check_nodejs",
16+
"check_python_packages",
17+
"check_ports",
18+
"check_database_connection",
19+
"check_all_dependencies",
20+
"start_dashboard_foreground",
21+
]

baselinr/ui/config_builder.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""Configuration builder for dashboard database connection."""
2+
3+
import logging
4+
5+
from ..config.schema import BaselinrConfig, DatabaseType
6+
7+
logger = logging.getLogger(__name__)
8+
9+
10+
def build_connection_string(config: BaselinrConfig) -> str:
11+
"""
12+
Build PostgreSQL connection string from BaselinrConfig.
13+
14+
The dashboard currently only supports PostgreSQL and SQLite, so we convert
15+
the storage connection config to a connection string.
16+
17+
Args:
18+
config: Baselinr configuration
19+
20+
Returns:
21+
PostgreSQL or SQLite connection string
22+
23+
Raises:
24+
ValueError: If the configured database type is not PostgreSQL or SQLite.
25+
"""
26+
conn_config = config.storage.connection
27+
conn_type = conn_config.type
28+
29+
if conn_type == DatabaseType.POSTGRES:
30+
host = conn_config.host or "localhost"
31+
port = conn_config.port or 5432
32+
username = conn_config.username or "baselinr"
33+
password = conn_config.password or ""
34+
database = conn_config.database
35+
36+
if password:
37+
return f"postgresql://{username}:{password}@{host}:{port}/{database}"
38+
else:
39+
return f"postgresql://{username}@{host}:{port}/{database}"
40+
elif conn_type == DatabaseType.SQLITE:
41+
filepath = conn_config.filepath
42+
if not filepath:
43+
raise ValueError("SQLite connection requires 'filepath' to be specified.")
44+
return f"sqlite:///{filepath}"
45+
else:
46+
raise ValueError(
47+
f"Dashboard currently only supports PostgreSQL or SQLite. "
48+
f"Configured type: {conn_type.value}"
49+
)

0 commit comments

Comments
 (0)