Skip to content

Repository files navigation

omelet-debug-panel

Angular debug panel for monitoring SQL queries, server timing, and debug login. Works with Angular 19+.

Features

  • Real-time SQL query count monitoring per HTTP request
  • Three display modes so the panel never fights your app for screen space: hidden (28px dot) - hud (single-line stat bar, default) - panel (full metrics)
  • Draggable anywhere, resizable, position/size/mode persisted in localStorage
  • Keyboard toggle (Ctrl+Shift+D by default), Esc collapses the panel to HUD
  • Server Timing header parsing and display
  • Peak query alert without hijacking the viewport (opt-in auto-expand)
  • Collapsible query distribution chart
  • Click-to-copy request details as Markdown
  • Debug login with JWT generation (quick role switch)
  • Configurable via injection token

Display modes

Mode Footprint How to get there
panel resizable, default 320x420 Click the HUD, or press the hotkey
hud ~160x28 stat bar showing peak / total / requests Default. Hotkey from panel, or minimize button
hidden 28x28 dot with alert badge Close button on HUD or panel

Drag the HUD or the panel header to move it. Drag the panel's top-left corner to resize, double click that corner to reset. Until it is resized manually the panel auto-fits its content up to a 420px cap, so an idle panel takes only the space it needs. Everything is stored under the omelet-debug-panel:ui localStorage key.

Installation

npm install omelet-debug-panel
# peer dependency
npm install jose

Setup

1. Provide configuration

// app.config.ts
import { provideDebugPanel, debugInterceptor } from 'omelet-debug-panel';
import { provideHttpClient, withInterceptors } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(
      withInterceptors([authInterceptor, debugInterceptor])
    ),
    provideDebugPanel({
      enabled: environment.DEBUG,        // toggle on/off
      peakQueryThreshold: 20,            // colors the peak stat red when exceeded
      defaultMode: 'hud',                // 'hidden' | 'hud' | 'panel' - first run only
      autoExpandOnAlert: false,          // true = open the panel when threshold exceeded
      hotkey: 'ctrl+shift+d',            // false disables the shortcut
      zIndex: 9999,
      login: {                           // optional: enable debug login tab
        apiUrl: environment.apiUrl,
        roles: [
          { value: 'Instructor', label: 'Instructor' },
          { value: 'Learner', label: 'Learner' },
        ],
        userByRoleEndpoint: '/internal/debug/user-by-role/', // default
      },
    }),
  ],
};

2. Add component to your app

// app.component.ts
import { OmeletDebugPanelComponent } from 'omelet-debug-panel';

@Component({
  imports: [OmeletDebugPanelComponent],
  template: `
    <router-outlet />
    <omelet-debug-panel />
  `,
})
export class AppComponent {}

3. Ensure PrimeIcons CSS is loaded

The panel uses PrimeIcons for icons. Add to your styles.css or angular.json:

@import 'primeicons/primeicons.css';

Backend Integration (Django)

The panel reads these HTTP response headers:

Header Description
X-DB-Query-Count Number of SQL queries executed
Server-Timing Detailed timing breakdown (spec)

With Django Debug Toolbar

pip install django-debug-toolbar
# settings.py
INSTALLED_APPS += ['debug_toolbar']
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']
DEBUG_TOOLBAR_CONFIG = {
    'SHOW_TOOLBAR_CALLBACK': lambda request: DEBUG,
}

Custom Middleware (recommended)

Add a middleware that exposes query count and timing headers:

# common/middleware/debug_headers.py
import time
from django.conf import settings
from django.db import connection


class DebugHeadersMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if not settings.DEBUG:
            return self.get_response(request)

        # Reset queries log
        connection.queries_log.clear()
        start = time.monotonic()

        response = self.get_response(request)

        elapsed = (time.monotonic() - start) * 1000
        query_count = len(connection.queries)
        sql_time = sum(float(q['time']) * 1000 for q in connection.queries)

        response['X-DB-Query-Count'] = str(query_count)
        response['Server-Timing'] = (
            f'total;dur={elapsed:.2f};desc="Total time", '
            f'db;dur={sql_time:.2f};desc="SQL {query_count} queries"'
        )

        # Expose headers to browser (CORS)
        existing = response.get('Access-Control-Expose-Headers', '')
        extra = 'X-DB-Query-Count, Server-Timing'
        response['Access-Control-Expose-Headers'] = (
            f'{existing}, {extra}' if existing else extra
        )

        return response
# settings.py
MIDDLEWARE = [
    'common.middleware.debug_headers.DebugHeadersMiddleware',
    # ... other middleware
]

CORS Headers

The browser can only read custom headers if they are exposed via CORS. Make sure your CORS config includes:

CORS_EXPOSE_HEADERS = ['X-DB-Query-Count', 'Server-Timing']

Or use the middleware above which adds Access-Control-Expose-Headers automatically.

API

Components

Component Selector Description
OmeletDebugPanelComponent <omelet-debug-panel> Main panel (use this one)
MetricsTabComponent <omelet-metrics-tab> Metrics tab only
LoginTabComponent <omelet-login-tab> Login tab only

Services

Service Description
DebugMetricsService Request metrics tracking
DebugPanelUiService Panel mode, position, size, persistence
DebugJwtService JWT token generation
DebugTokenService Token storage (localStorage)

Functions

Function Description
provideDebugPanel(config) Provider factory
debugInterceptor HTTP interceptor

Interfaces

interface DebugPanelConfig {
  enabled: boolean;
  peakQueryThreshold?: number;   // default: 20
  defaultMode?: 'hidden' | 'hud' | 'panel'; // default: 'hud'
  autoExpandOnAlert?: boolean;   // default: false
  hotkey?: string | false;       // default: 'ctrl+shift+d'
  zIndex?: number;               // default: 9999
  storageKey?: string;           // default: 'omelet-debug-panel:ui'
  login?: {
    apiUrl: string;
    roles?: { value: string; label: string }[];
    userByRoleEndpoint?: string; // default: '/internal/debug/user-by-role/'
  };
}

interface RequestMetric {
  timestamp: Date;
  method: string;
  url: string;
  queryCount: number;
  duration?: number;
  status?: number;
  serverTiming?: ServerTimingEntry[];
}

interface ServerTimingEntry {
  name: string;
  dur?: number;
  desc?: string;
}

Markdown Copy Format

Clicking a request in the panel copies this format to clipboard:

## GET https://api.example.com/api/courses/

| Header | Value |
|--------|-------|
| Status | 200 |
| DB Queries | 15 |

### Server Timing

| Metric | Duration |
|--------|----------|
| Total time | 314.19ms |
| SQL 35 queries | 177.74ms |

Development

npm install
npm run build        # build to dist/
npm run build:watch  # watch mode

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages