Widget System Architecture

Architecture of the dynamic widget and dashboard system

🧩 Widget System Architecture

The Widget System provides a flexible, responsive grid layout for dynamic dashboards and pages.

It integrates seamlessly with the Module System to allow modules to expose embeddable components as widgets.


🎯 Design Goals

  1. Integration: Reuse ModuleEmbeddableComponent definitions.
  2. Responsiveness: Intelligent layout adaptation for all devices.
  3. Resilience: Error boundaries to isolate widget failures.
  4. Performance: OnPush change detection and lazy loading.

🏗️ Component Architecture

1. WidgetGridComponent

The main container. Renders widgets using CSS Grid.

2. WidgetContainerComponent

The wrapper for individual widgets.

3. BaseWidgetComponent (Optional)

An abstract class that widgets can extend for helper methods.


📱 Responsive Strategy

We use a Two-Phase responsive strategy to ensure great UX without configuration hell.

Phase 1: Auto-Shrink (Default)

Smart logic automatically adapts desktop configurations for mobile.

Phase 2: Overrides (Advanced)

Specific widgets can provide override configurations for fine-grained control.

position: {
  x: 0, y: 0, width: 6, height: 4,
  responsive: {
    mobile: { height: 2 } // Shorter on mobile
  }
}

🔌 Integration Patterns

Dashboard Integration

Dashboards consume AppConfigService to get the list of ResolvedWidgetConfig.

<lib-gs-widget-grid [widgets]="enabledWidgets()" [gridConfig]="config" />

Module Registration

Modules define widgets in their manifest. The system automatically registers them.

embeddableComponents: [
  {
    id: 'my-module:widget',
    componentType: MyWidgetComponent,
    category: 'widget'
  }
]

📊 Data Models

GridConfig

Defines the structure of the grid.

interface GridConfig {
  columns: number;
  gap: number;
  rowHeight: number | 'auto';
  breakpoints: { ... };
}

ResolvedWidgetConfig

The runtime configuration for a widget instance.

interface ResolvedWidgetConfig {
  id: string;
  componentType: Type<unknown>;
  position: { x, y, width, height };
  inputs?: Record<string, any>;
}

🛡️ Error Handling

The WidgetContainerComponent acts as a firewall. If a widget throws an error:

  1. The error is caught.
  2. The widget is replaced by a WidgetErrorComponent.
  3. The rest of the dashboard continues to function.
  4. Users can try to "Retry" just that specific widget.

Status: ✅ Production Architecture Last Updated: December 3, 2025